Type::Tiny::Manual::Libraries - phpMan

Command: man perldoc info search(apropos)  


Sections
NAME MANUAL NEXT STEPS AUTHOR COPYRIGHT AND LICENCE DISCLAIMER OF WARRANTIES
NAME
    Type::Tiny::Manual::Libraries - defining your own type libraries

MANUAL
  Defining a Type
    A type is an object and you can create a new one using the constructor:

      use Type::Tiny;

      my $type = Type::Tiny->new(%args);

    A full list of the available arguments can be found in the Type::Tiny
    documentation, but the most important ones to begin with are:

    "name"
        The name of your new type. Type::Tiny uses a convention of
        UpperCamelCase names for type constraints. The type name may also
        begin with one or two leading underscores to indicate a type
        intended for internal use only. Types using non-ASCII characters may
        cause problems on older versions of Perl (pre-5.8).

        Although this is optional and types may be anonymous, a name is
        required for a type constraint to added to a type library.

    "constraint"
        A code reference checking $_ and returning a boolean. Alternatively,
        a string of Perl code may be provided.

        If you've been paying attention, you can probably guess that the
        string of Perl code may result in more efficient type checks.

    "parent"
        An existing type constraint to inherit from. A value will need to
        pass the parent constraint before its own constraint would be
        called.

          my $Even = Type::Tiny->new(
            name       => 'EvenNumber',
            parent     => Types::Standard::Int,
            constraint => sub {
              # in this sub we don't need to check that $_ is an Int
              # because the parent will take care of that!

              $_ % 2 == 0
            },
          );

        Although the "parent" is optional, it makes sense whenever possible
        to inherit from an existing type constraint to benefit from any
        optimizations or XS implementations they may provide.

  Defining a Library
    A library is a Perl module that exports type constraints as subs.
    Types::Standard, Types::Common::Numeric, and Types::Common::String are
    type libraries that are bundled with Type::Tiny.

    To create a type library, create a package that inherits from
    Type::Library.

      package MyTypes {
        use Type::Library -base;

        ...; # your type definitions go here
      }

    The "-base" flag is just a shortcut for:

      package MyTypes {
        use Type::Library;
        our @ISA = 'Type::Library';
      }

    You can add types like this:

      package MyTypes {
        use Type::Library -base;

        my $Even = Type::Tiny->new(
          name       => 'EvenNumber',
          parent     => Types::Standard::Int,
          constraint => sub {
            # in this sub we don't need to check that $_ is an Int
            # because the parent will take care of that!

            $_ % 2 == 0
          },
        );

        __PACKAGE__->add_type($Even);
      }

    There is a shortcut for adding types if they're going to be blessed
    Type::Tiny objects and not, for example, a subclass of Type::Tiny. You
    can just pass %args directly to "add_type".

      package MyTypes {
        use Type::Library -base;

        __PACKAGE__->add_type(
          name       => 'EvenNumber',
          parent     => Types::Standard::Int,
          constraint => sub {
            # in this sub we don't need to check that $_ is an Int
            # because the parent will take care of that!

            $_ % 2 == 0
          },
        );
      }

    The "add_type" method returns the type it just added, so it can be
    stored in a variable.

      my $Even = __PACKAGE__->add_type(...);

    This can be useful if you wish to use $Even as the parent type to some
    other type you're going to define later.

    Here's a bigger worked example:

      package Example::Types {
        use Type::Library -base;
        use Types::Standard -types;
        use DateTime;

        # Type::Tiny::Class is a subclass of Type::Tiny for creating
        # InstanceOf-like types. It's kind of better though because
        # it does cool stuff like pass through $type->new(%args) to
        # the class's constructor.
        #
        my $dt = __PACKAGE__->add_type(
          Type::Tiny::Class->new(
            name    => 'Datetime',
            class   => 'DateTime',
          )
        );

        my $dth = __PACKAGE__->add_type(
          name    => 'DatetimeHash',
          parent  => Dict[
            year       => Int,
            month      => Optional[ Int ],
            day        => Optional[ Int ],
            hour       => Optional[ Int ],
            minute     => Optional[ Int ],
            second     => Optional[ Int ],
            nanosecond => Optional[ Int ],
            time_zone  => Optional[ Str ],
          ],
        );

        my $eph = __PACKAGE__->add_type(
          name    => 'EpochHash',
          parent  => Dict[ epoch => Int ],
        );

        # Can't just use "plus_coercions" method because that creates
        # a new anonymous child type to add the coercions to. We want
        # to add them to the type which exists in this library.
        #
        $dt->coercion->add_type_coercions(
          Int,    q{ DateTime->from_epoch(epoch => $_) },
          Undef,  q{ DateTime->now() },
          $dth,   q{ DateTime->new(%$_) },
          $eph,   q{ DateTime->from_epoch(%$_) },
        );

        __PACKAGE__->make_immutable;
      }

    "make_immutable" freezes to coercions of all the types in the package,
    so no outside code can tamper with the coercions, and allows Type::Tiny
    to make optimizations to the coercions, knowing they won't later be
    altered. You should always do this at the end.

    The library will export types Datetime, DatetimeHash, and EpochHash. The
    Datetime type will have coercions from Int, Undef, DatetimeHash, and
    EpochHash.

  Extending Libraries
    Type::Utils provides a helpful function "extends".

      package My::Types {
        use Type::Library -base;
        use Type::Utils qw( extends );

        BEGIN { extends("Types::Standard") };

        # define your own types here
      }

    The "extends" function (which you should usually use in a "BEGIN { }"
    block not only loads another type library, but it also adds all the
    types from it to your library.

    This means code using the above My::Types doesn't need to do:

      use Types::Standard qw( Str );
      use My::Types qw( Something );

    It can just do:

      use My::Types qw( Str Something );

    Because all the types from Types::Standard have been copied across into
    My::Types and are also available there.

    "extends" can be passed a list of libraries; you can inherit from
    multiple existing libraries. It can also recognize and import types from
    MooseX::Types, MouseX::Types, and Specio::Exporter libraries.

    Since Type::Library 1.012, there has been a shortcut for "extends".

      package My::Types {
        use Type::Library -extends => [ 'Types::Standard' ];

        # define your own types here
      }

    The "-extends" flag takes an arrayref of type libraries to extend. It
    automatically implies "-base" so you don't need to use both.

  Custom Error Messages
    A type constraint can have custom error messages. It's pretty simple:

      Type::Tiny->new(
        name       => 'EvenNumber',
        parent     => Types::Standard::Int,
        constraint => sub {
          # in this sub we don't need to check that $_ is an Int
          # because the parent will take care of that!

          $_ % 2 == 0
        },
        message   => sub {
          sprintf '%s is not an even number', Type::Tiny::_dd($_);
        },
      );

    The message coderef just takes a value in $_ and returns a string. It
    may use "Type::Tiny::_dd()" as a way of pretty-printing a value. (Don't
    be put off by the underscore in the function name. "_dd()" is an
    officially supported part of Type::Tiny's API now.)

    You don't have to use "_dd()". You can generate any error string you
    like. But "_dd()" will help you make undef and the empty string look
    different, and will pretty-print references, and so on.

    There's no need to supply an error message coderef unless you really
    want custom error messages. The default sub should be reasonable.

  Inlining
    In Perl, sub calls are relatively expensive in terms of memory and CPU
    use. The PositiveInt type inherits from Int which inherits from Num
    which inherits from Str which inherits from Defined which inherits from
    Item which inherits from Any.

    So you might think that to check of $value is a PositiveInt, it needs to
    be checked all the way up the inheritance chain. But this is where one
    of Type::Tiny's big optimizations happens. Type::Tiny can glue together
    a bunch of checks with a stringy eval, and get a single coderef that can
    do all the checks in one go.

    This is why when Type::Tiny gives you a choice of using a coderef or a
    string of Perl code, you should usually choose the string of Perl code.
    A single coderef can "break the chain".

    But these automatically generated strings of Perl code are not always as
    efficient as they could be. For example, imagine that HashRef is defined
    as:

      my $Defined = Type::Tiny->new(
        name       => 'Defined',
        constraint => 'defined($_)',
      );
      my $Ref = Type::Tiny->new(
        name       => 'Ref',
        parent     => $Defined,
        constraint => 'ref($_)',
      );
      my $HashRef = Type::Tiny->new(
        name       => 'HashRef',
        parent     => $Ref,
        constraint => 'ref($_) eq "HASH"',
      );

    Then the combined check is:

      defined($_) and ref($_) and ref($_) eq "HASH"

    Actually in practice it's even more complicated, because Type::Tiny
    needs to localize and set $_ first.

    But in practice, the following should be a sufficient check:

      ref($_) eq "HASH"

    It is possible for the HashRef type to have more control over the string
    of code generated.

      my $HashRef = Type::Tiny->new(
        name       => 'HashRef',
        parent     => $Ref,
        constraint => 'ref($_) eq "HASH"',
        inlined    => sub {
          my $varname = pop;
          sprintf 'ref(%s) eq "HASH"', $varname;
        },
      );

    The inlined coderef gets passed the name of a variable to check. This
    could be '$_' or '$var' or "$some{deep}{thing}[0]". Because it is passed
    the name of a variable to check, instead of always checking $_, this
    enables very efficient checking for parameterized types.

    Although in this case, the inlining coderef is just returning a string,
    technically it returns a list of strings. If there's multiple strings,
    Type::Tiny will join them together in a big "&&" statement.

    As a special case, if the first item in the returned list of strings is
    undef, then Type::Tiny will substitute the parent type constraint's
    inlined string in its place. So an inlieing coderef for even numbers
    might be:

      Type::Tiny->new(
        name       => 'EvenNumber',
        parent     => Types::Standard::Int,
        constraint => sub { $_ % 2 == 0 },
        inlined    => sub {
          my $varname = pop;
          return (undef, "$varname % 2 == 0");
        },
      );

    Even if you provide a coderef as a string, an inlining coderef has the
    potential to generate more efficient code, so you should consider
    providing one.

  Pre-Declaring Types
      use Type::Library -base,
        -declare => qw( Foo Bar Baz );

    This declares types Foo, Bar, and Baz at compile time so they can safely
    be used as barewords in your type library.

    This also allows recursively defined types to (mostly) work!

      use Type::Library -base,
        -declare => qw( NumericArrayRef );
      use Types::Standard qw( Num ArrayRef );

      __PACKAGE__->add_type(
        name     => NumericArrayRef,
        parent   => ArrayRef->of( Num | NumericArrayRef ),
      );

    (Support for recursive type definitions added in Type::Library
    1.009_000.)

  Parameterizable Types
    This is probably the most "meta" concept that is going to be covered.
    Building your own type constraint that can be parameterized like
    ArrayRef or HasMethods.

    The type constraint we'll build will be MultipleOf[$i] which checks that
    an integer is a multiple of $i.

      __PACKAGE__->add_type(
        name       => 'MultipleOf',
        parent     => Int,

        # This coderef gets passed the contents of the square brackets.
        constraint_generator => sub {
          my $i = assert_Int(shift);
          # needs to return a coderef to use as a constraint for the
          # parameterized type
          return sub { $_ % $i == 0 };
        },

        # optional but recommended
        inline_generator => sub {
          my $i = shift;
          return sub {
            my $varname = pop;
            return (undef, "$varname % $i == 0");
          };
        },

        # probably the most complex bit
        coercion_generator => sub {
          my $i = $_[2];
          require Type::Coercion;
          return Type::Coercion->new(
            type_coercion_map => [
              Num, qq{ int($i * int(\$_/$i)) }
            ],
          );
        },
      );

    Now we can define an even number like this:

      __PACKAGE__->add_type(
        name     => 'EvenNumber',
        parent   => __PACKAGE__->get_type('MultipleOf')->of(2),
        coercion => 1,  # inherit from parent
      );

    Note that it is possible for a type constraint to have a "constraint"
    *and* a "constraint_generator".

      BaseType          # uses the constraint
      BaseType[]        # constraint_generator with no arguments
      BaseType[$x]      # constraint_generator with an argument

    In the MultipleOf example above, MultipleOf[] with no number would throw
    an error because of "assert_Int(shift)" not finding an integer.

    But it is certainly possible for BaseType[] to be meaningful and
    distinct from "BaseType".

    For example, Tuple is just the same as ArrayRef and accepts any arrayref
    as being valid. But Tuple[] will only accept arrayrefs with zero
    elements in them. (Just like Tuple[Any,Any] will only accept arrayrefs
    with two elements.)

NEXT STEPS
    After that last example, probably have a little lie down. Once you're
    recovered, here's your next step:

    *   Type::Tiny::Manual::UsingWithMoose

        How to use Type::Tiny with Moose, including the advantages of
        Type::Tiny over built-in type constraints, and Moose-specific
        features.

AUTHOR
    Toby Inkster <tobyink AT cpan.org>.

COPYRIGHT AND LICENCE
    This software is copyright (c) 2013-2014, 2017-2021 by Toby Inkster.

    This is free software; you can redistribute it and/or modify it under
    the same terms as the Perl 5 programming language system itself.

DISCLAIMER OF WARRANTIES
    THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
    WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
    MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.


Generated by phpMan Author: Che Dong On Apache Under GNU General Public License - MarkDown Format
2026-05-23 08:47 @216.73.217.24 CrawledBy Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com)
Valid XHTML 1.0 TransitionalValid CSS!

^_back to top