Dave Rolsky > Type > Type



Annotate this POD

Module Version: 0.05   Source  


Type - Type constraints and coercions for Perl


version 0.05


  package MyApp::Type::Library;

  use Type::Declare;
  use Type::Library::Builtins;

      parent => t('Int'),
      inline => sub {

  # or ...

      parent => t('Int'),

      parent => t(
          of => t('PositiveInt'),

      from  => t('PositiveInt'),




WARNING: This thing is very alpha.

The Type distribution provides classes for representing type constraints and coercion, along with syntax sugar for declaring them.





At it's core, a type is simply a constraint. A constraint is code that checks a value and returns true or false. Most constraints are represented by Type::Constraint::Simple objects though there are other type constraint classes for specialized kinds of constraints.







      Maybe (of `a)
              ScalarRef (of `a)
              ArrayRef (of `a)
              HashRef (of `a)

The Item type accepts anything and everything.

The Bool type only accepts undef, 0, or 1.

The Undef type only accepts undef.

The Defined type accepts anything except undef.


The ClassName type constraint checks that the name is valid and that the class is loaded.

The FileHandle type accepts either a glob, a scalar filehandle, or anything that isa IO::Handle.





For types where overloading makes sense, we explicitly check that the object provides the type overloading we expect. We do not simply try to use the object as the type and question and hope it works. This means that these checks effective ignore the fallback setting for the overloaded object. In other words, an object that overloads stringification will not pass the Bool type check unless it also overloads boolification.


The Bool type accepts an object that provides bool overloading.

The Str type accepts an object that provides string (q{""}) overloading.

The Num type accepts an object that provides numeric '0+'} overloading. The Int type does as well, but it will check that the overloading returns an actual integer.

The ClassName type will accept an object with string overloading that returns a class name.

To make this all more confusing, the Value type will never accept an object, even though some it's subtypes will.

The various reference types all accept objects which provide the appropriate overloading. The FileHandle type accepts an object which overloads globification as long as the returned glob is an open filehandle.


Any type followed by a type parameter of `a in the hierarchy above can be parameterized. The parameter is itself a type, so you can say you want an "ArrayRef of Int", or even an "ArrayRef of HashRef of ScalarRef of ClassName".

When they are parameterized, the ScalarRef and ArrayRef types check that the value(s) they refer to match the type parameter. For the HashRef type, the parameter applies to the values (keys are never checked).


The Maybe type is a special parameterized type. It allows for either undef or a value. All by itself, it is meaningless, since it is equivalent to "Maybe of Item", which is equivalent to Item. When parameterized, it accepts either an undef or the its parameter.

This is useful for optional attributes or parameters. However, whenever possible, you're often better off making the parameter not required at all. This usually makes for a simpler API.




The registry is managed internally by the Type distribution's modules, and is not exposed to your code. To access a type, you always call t('TypeName').

This returns the named type, or dies if no such type exists.

Because types are always copied on import, it's safe to create coercions on any type. Your coercion from Str to Int will not be seen by any other package, unless that package explicitly imports your Int type.

When you import types, you import every type defined in the package you import from. However, you can overwrite an imported type with your own type definition. You cannot define the same type twice internally.


By default, all types created inside a package are invisible to other packages. If you want to create a type library, you need to inherit from Type::Exporter package:

  package MyApp::Type::Library;

  use parent 'Type::Exporter';

  use Type::Declare;
  use Type::Library::Builtins;

      parent => t('Str'),

Now the MyApp::Type::Library package will export a single type named Foo. It does not (yet) re-export the types provided by Type::Library::Builtins.


  package MyApp::Type::Library;

  use parent 'Type::Exporter';

  use Type::Declare;
  use Type::Library::Builtins -reexport;

  declare( 'Foo, ... );

Now MyApp::Types::Library exports any types it defines, as well as all the types defined in Type::Library::Builtins.



Moose, MooseX::Types, and Type ^


Here are some of the salient differences:



For now, the current code is a proof of concept for the design.


Please report any bugs or feature requests to bug-type@rt.cpan.org, or through the web interface at http://rt.cpan.org. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.







Dave Rolsky <autarch@urth.org>


This software is Copyright (c) 2012 by Dave Rolsky.

This is free software, licensed under:

  The Artistic License 2.0 (GPL Compatible)
syntax highlighting: