{
    "mode": "perldoc",
    "parameter": "Type::Tiny::Manual::Coercions",
    "section": "",
    "url": "https://www.chedong.com/phpMan.php/perldoc/Type%3A%3ATiny%3A%3AManual%3A%3ACoercions/json",
    "generated": "2026-06-12T06:50:53Z",
    "sections": {
        "NAME": {
            "content": "Type::Tiny::Manual::Coercions - advanced information on coercions\n",
            "subsections": []
        },
        "MANUAL": {
            "content": "This section of the manual assumes you've already read Type::Tiny::Manual::UsingWithMoo.\n\nType::Tiny takes a slightly different approach to type constraints from Moose. In Moose, there\nis a single flat namespace for type constraints. Moose defines a type constraint called Str for\nstrings and a type constraint called ArrayRef for arrayrefs. If you want to define strings\ndifferently (maybe you think that the empty string doesn't really count as a string, or maybe\nyou think objects overloading \"q[\"\"]\" should count as strings) then you can't call it Str; you\nneed to choose a different name.\n\nWith Type::Tiny, two type libraries can each offer a string type constraint with their own\ndefinitions for what counts as a string, and you can choose which one to import, or import them\nboth with different names:\n\nuse Some::Types qw( Str );\nuse Other::Types \"Str\" => { -as => \"Str2\" };\n\nThis might seem to be a small advantage of Type::Tiny, but where this global-versus-local\nphilosophy really makes a difference is coercions.\n\nLet's imagine for a part of your application that deals with reading username and password data\nyou need to have a \"username:password\" string. You may wish to accept a \"[$username, $password]\"\narrayref and coerce it to a string using \"join \":\", @$arrayref\". But another part of your\napplication deals with slurping log files, and wants to coerce a string from an arrayref using\n\"join \"\\n\", @$arrayref\". These are both perfectly sensible ways to coerce an arrayref. In Moose,\na typical way to do this would be:\n\npackage My::UserManager {\nuse Moose;\nuse Moose::Util::TypeConstraints;\n\ncoerce 'Str',\nfrom 'ArrayRef', via { join \":\", @$ };\n\n...;\n}\n\npackage My::LogReader {\nuse Moose;\nuse Moose::Util::TypeConstraints;\n\ncoerce 'Str',\nfrom 'ArrayRef', via { join \"\\n\", @$ };\n\n...;\n}\n\nHowever, because in Moose all types and coercions are global, if both these classes are loaded,\nonly one of them will work. One class will overrule the other's coercion. Which one \"wins\" will\ndepend on load order.\n\nIt is possible to solve this with Moose native types, but it requires extra work. (The solution\nis for My::UserManager and My::LogReader to each create a subtype of Str and define the coercion\non that subtype instead of on Str directly.)\n\nType::Tiny solves this in two ways:\n\n1.  Type::Tiny makes it possible for type libraries to \"protect\" their type constraints to\nprevent external code from adding new coercions to them.\n\n$type->coercion->freeze();\n\nYou can freeze coercions for your entire type library using:\n\nPACKAGE->makeimmutable;\n\nIf you try to add coercions to a type constraint that has frozen coercions, it will throw an\nerror.\n\nuse Types::Standard qw( Str ArrayRef );\n\nStr->coercion->addtypecoercions(\nArrayRef, sub { join \"\\n\", @$ },\n);\n\n2.  Type::Tiny makes the above-mentioned pattern of adding coercions to a subtype much easier.\n\nuse Types::Standard ( Str ArrayRef );\n\nmy $subtype = Str->pluscoercions(\nArrayRef, sub { join \"\\n\", @$ },\n);\n\nThe \"pluscoercions\" method creates a new child type, adds new coercions to it, copies any\nexisting coercions from the parent type, and then freezes coercions for the new child type.\n\nThe end result is you now have a \"copy\" of Str that can coerce from ArrayRef but other\ncopies of Str won't be affected by your coercion.\n",
            "subsections": [
                {
                    "name": "Defining Coercions within Type Libraries",
                    "content": "Some coercions like joining an arrayref to make a string are not going to be coercions that\neverybody will agree on. Join with a line break in between them as above? Or with a colon, a\ntab, a space, some other chanaracter? It depends a lot on your application.\n\nOthers, like coercing a Path::Tiny object from a string, are likely to be very obvious. It is\nthis kind of coercion that it makes sense to define within the library itself so it's available\nto any packages that use the library.\n\nmy $pt = PACKAGE->addtype(\nType::Tiny::Class->new(\nname    => 'Path',\nclass   => 'Path::Tiny',\n),\n);\n\n$pt->coercion->addtypecoercions(\nStr, q{ Path::Tiny::path($) },\n);\n\n$pt->coercion->freeze;\n"
                },
                {
                    "name": "Tweak Coercions Outside Type Libraries",
                    "content": "The \"pluscoercions\" method creates a new type constraint with additional coercions. If the\noriginal type already had coercions, the new coercions have a higher priority.\n\nThere's also a \"plusfallbackcoercions\" method which does the same as \"pluscoercions\" but adds\nthe new coercions with a lower priority than any existing ones.\n\nType::Tiny::Class provides a \"plusconstructors\" method as a shortcut for coercing via a\nconstructor method. The following two are the same:\n\nPath->plusconstructors(Str, \"new\")\n\nPath->pluscoercions(Str, q{ Path::Tiny->new($) })\n\nTo create a type constraint without particular existing coercions, you can use\n\"minuscoercions\". The following uses the Datetime type defined in\nType::Tiny::Manual::Libraries, removing the coercion from Int but keeping the coercions from\nUndef and Dict.\n\nuse Types::Standard qw( Int );\nuse Example::Types qw( Datetime );\n\nhas startdate => (\nis      => 'ro',\nisa     => Datetime->minuscoercions(Int),\ncoerce  => 1,\n);\n\nThere's also a \"nocoercions\" method that creates a subtype with no coercions at all. This is\nmost useful either to create a \"blank slate\" for \"pluscoercions\":\n\nmy $Path = Path->nocoercions->pluscoercions(Str, sub { ... });\n\nOr to disable coercions for Type::Params. Type::Params will always automatically coerce a\nparameter if there is a coercion for that type.\n\nuse Types::Standard qw( Object );\nuse Types::Common::String qw( UpperCaseStr );\nuse Type::Params;\n\nsub setaccountname {\nstate $check = compile( Object, UpperCaseStr->nocoercions );\nmy ($self, $name) = $check->(@);\n$self->accountname($name);\n$self->db->update($self);\nreturn $self;\n}\n\n# This will die instead of coercing from lowercase\n$robert->setaccountname('bob');\n"
                },
                {
                    "name": "Named Coercions",
                    "content": "A compromise between defining a coercion in the type library or defining them in the package\nthat uses the type library is for a type library to define a named collection of coercions which\ncan be optionally added to a type constraint.\n\n{\npackage MyApp::Types;\nuse Type::Library -base;\nuse Type::Utils qw( extends );\n\nBEGIN { extends 'Types::Standard' };\n\nPACKAGE->addcoercion(\nname              => \"FromLines\",\ntypeconstraint   => ArrayRef,\ntypecoercionmap => [\nStr,     q{ [split /\\n/] },\nUndef,   q{ [] },\n],\n);\n}\n\nThis set of coercions has a name and can be imported and used:\n\nuse MyApp::Types qw( ArrayRef FromLines );\n\nhas lines => (\nis      => 'ro',\nisa     => ArrayRef->pluscoercions( FromLines ),\ncoerce  => 1,\n);\n\nTypes::Standard defines a named coercion MkOpt designed to be used for OptList.\n\nuse Types::Standard qw( OptList MkOpt );\nmy $OptList = OptList->pluscoercions(MkOpt);\n"
                },
                {
                    "name": "Parameterized Coercions",
                    "content": "Named coercions can also be parameterizable.\n\nmy $ArrayOfLines = ArrayRef->pluscoercions( Split[ qr{\\n} ] );\n\nTypes::Standard defines Split and Join parameterizable coercions.\n\nViewing the source code for Types::Standard should give you hints as to how they are\nimplemented.\n\n\"Deep\" Coercions\nCertain parameterized type constraints can automatically acquire coercions if their parameters\nhave coercions. For example:\n\nArrayRef[ Int->pluscoercions(Num, q{int($)}) ]\n\n... does what you mean!\n\nThe parameterized type constraints that do this magic include the following ones from\nTypes::Standard:\n\n*   ScalarRef\n\n*   ArrayRef\n\n*   HashRef\n\n*   Map\n\n*   Tuple\n\n*   CycleTuple\n\n*   Dict\n\n*   Optional\n\n*   Maybe\n\nImagine we're defining a type Paths in a type library:\n\nPACKAGE->addtype(\nname      => 'Paths',\nparent    => ArrayRef[Path],\n);\n\nThe Path type has a coercion from Str, so Paths should be able to coerce from an arrayref of\nstrings, right?\n\n*Wrong!* Although ArrayRef[Path] could coerce from an arrayref of strings, Paths is a separate\ntype constraint which, although it inherits from ArrayRef[Path] has its own (currently empty)\nset of coercions.\n\nBecause that is often not what you want, Type::Tiny provides a shortcut when declaring a subtype\nto copy the parent type constraint's coercions:\n\nPACKAGE->addtype(\nname      => 'Paths',\nparent    => ArrayRef[Path],\ncoercion  => 1,   # inherit\n);\n\nNow Paths can coerce from an arrayref of strings.\n\nDeep Caveat\nCurrently there exists ill-defined behaviour resulting from mixing deep coercions and mutable\n(non-frozen) coercions. Consider the following:\n\nclasstype Path, { class => \"Path::Tiny\" };\ncoerce Path,\nfrom Str, via { \"Path::Tiny\"->new($) };\n\ndeclare Paths, as ArrayRef[Path], coercion => 1;\n\ncoerce Path,\nfrom InstanceOf[\"My::File\"], via { $->getpath };\n\nAn arrayref of strings can now be coerced to an arrayref of Path::Tiny objects, but is it also\nnow possible to coerce an arrayref of My::File objects to an arrayref of Path::Tiny objects?\n\nCurrently the answer is \"no\", but this is mostly down to implementation details. It's not clear\nwhat the best way to behave in this situation is, and it could start working at some point in\nthe future.\n\nThis is why you should freeze coercions.\n"
                },
                {
                    "name": "Chained Coercions",
                    "content": "Consider the following type library:\n\npackage Types::Geometric {\nuse Type::Library -base, -declare => qw(\nVectorArray\nVectorArray3D\nPoint\nPoint3D\n);\nuse Type::Utils;\nuse Types::Standard qw( Num Tuple InstanceOf );\n\ndeclare VectorArray,\nas Tuple[Num, Num];\n\ndeclare VectorArray3D,\nas Tuple[Num, Num, Num];\n\ncoerce VectorArray3D,\nfrom VectorArray, via {\n[ @$, 0 ];\n};\n\nclasstype Point, { class => \"Point\" };\n\ncoerce Point,\nfrom VectorArray, via {\nPoint->new(x => $->[0], y => $->[1]);\n};\n\nclasstype Point3D, { class => \"Point3D\" };\n\ncoerce Point3D,\nfrom VectorArray3D, via {\nPoint3D->new(x => $->[0], y => $->[1], z => $->[2]);\n},\nfrom Point, via {\nPoint3D->new(x => $->x, y => $->y, z => 0);\n};\n}\n\nGiven an arrayref \"[1, 1]\" you might reasonably expect it to be coercible to a Point3D object;\nit matches the type constraint VectorArray so can be coerced to VectorArray3D and thus to\nPoint3D.\n\nHowever, Type::Coercion does not automatically chain coercions like this. Firstly, it would be\nincompatible with Moose's type coercion system which does not chain coercions. Secondly, it's\nambiguous; in our example, the arrayref could be coerced along two different paths (via\nVectorArray3D or via Point); in this case the end result would be the same, but in other cases\nit might not. Thirdly, it runs the risk of accidentally creating loops.\n\nDoing the chaining manually though is pretty simple. Firstly, we'll take note of the\n\"coercibles\" method in Type::Tiny. This method called as \"VectorArray3D->coercibles\" returns a\ntype constraint meaning \"anything that can be coerced to a VectorArray3D\".\n\nSo we can define the coercions for Point3D as:\n\ncoerce Point3D,\nfrom VectorArray3D->coercibles, via {\nmy $tmp = toVectorArray3D($);\nPoint3D->new(x => $tmp->[0], y => $tmp->[1], z => $tmp->[2]);\n},\nfrom Point, via {\nPoint3D->new(x => $->x, y => $->y, z => 0);\n};\n\n... and now coercing from \"[1, 1]\" will work.\n"
                }
            ]
        },
        "SEE ALSO": {
            "content": "Moose::Manual::BestPractices,\n<https://web.archive.org/web/20090624164256/http://www.catalyzed.org/2009/06/keeping-your-coerci\nons-to-yourself.html>, MooseX::Types::MoreUtils.\n",
            "subsections": []
        },
        "NEXT STEPS": {
            "content": "After that last example, probably have a little lie down. Once you're recovered, here's your\nnext step:\n\n*   Type::Tiny::Manual::AllTypes\n\nAn alphabetical list of all type constraints bundled with Type::Tiny.\n",
            "subsections": []
        },
        "AUTHOR": {
            "content": "Toby Inkster <tobyink@cpan.org>.\n",
            "subsections": []
        },
        "COPYRIGHT AND LICENCE": {
            "content": "This software is copyright (c) 2013-2014, 2017-2021 by Toby Inkster.\n\nThis is free software; you can redistribute it and/or modify it under the same terms as the Perl\n5 programming language system itself.\n",
            "subsections": []
        },
        "DISCLAIMER OF WARRANTIES": {
            "content": "THIS PACKAGE IS PROVIDED \"AS IS\" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\nWITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.\n",
            "subsections": []
        }
    },
    "summary": "Type::Tiny::Manual::Coercions - advanced information on coercions",
    "flags": [],
    "examples": [],
    "see_also": []
}