NAME

Variable::Strongly::Typed - Let some variables be strongly typed

VERSION

This document describes Variable::Strongly::Typed version 1.0.0

SYNOPSIS

use Variable::Strongly::Typed;

my $int             :TYPE('int');       # must have an 'int' value
my $float           :TYPE('float');     # must have a 'float' value
my $string          :TYPE('string');    # must not be a reference
my $file            :TYPE('IO::File');  # must be an IO::File
my @array_of_ints   :TYPE('int');       # Each slot must contain 
                                        #   an int
my %hash_of_floats  :TYPE('float');     # Each value must be a float

my $int_own_error   :TYPE('int', \&my_own_error_handler);
                                        # Roll my own error handler

my @array_of_rgb :TYPE(\&red_green_blue); # my enumerated type

# For subs!!
sub return_an_int :TYPE('int') {
    # .. do some stuff ..
    return $something;
}

# ... and later ...

$int = 23;          # All is well
$int = 'howdy!';    # This line will croak with a good error message

$float = 3.23;              # All is well, nothing to see here
$float = new XML::Parser;   # croak!

$array_of_ints[23] = 44;    # Groovy
$array_of_ints[12] = 'yah'; # croak!

$hash_of_floats{pi} = 3.14159;      # no problem
$hash_of_floats{e}  = new IO::File; # croak!

# Return 1 if this val is RED, BLUE, or GREEN
#   0 otherwise
sub red_green_blue {
    local $_ = shift;

    /\A RED \z/xms || /\A BLUE \z/xms || /\A GREEN \z/xms;
}

$array_of_my_very_own_types[23] = 99;       # croak!
$array_of_my_very_own_types[2] = 'BLUE';    # OK!

$int_own_error = 'lksdklwe';    # The sub 'my_own_error_hanlder' 
                                #   will be #   called with the 
                                #   offending value

my $got_it = return_an_int();   # Will 'croak' (or call your error 
                                #   function) #   if this sub doesn't 
                                #   return an 'int'

DESCRIPTION

This modules allow you to strongly type your variables. Also known as the 'no fun' module - it can greatly enhance you code's quality and robustness.

By enforcing types on some (or all) of your variables you will eliminate a large class of careless (& not so careless) errors.

This could also aid an editor or code-browsing tools to verify code correctness without having to execute the script.

INTERFACE

Variable types are specified using the 'TYPE' attribute. There are currently 7 builtin types:

'int' => /\A \d+ \z/xms;
'string' => anything that's not a reference (!ref)
'float' => standard float regex
'bool' => same as 'int'
'SCALAR' => unblessed scalar ref
'ARRAY' => unblessed array ref
'HASH' => unblessed hash ref

You can also specify a class name like 'XML::Parser' - note this is NOT the same as 'HASH' which represents an unblessed HASH reference.

Note when specifying 'XML::Parser' assigning 'XML::Parser' or any subclass of 'XML::Parser' will be valid - it does a $value->isa('XML::Parser') (or whatever the type you specified was) to test the value.

If you try to assign an illegal value to your variable the assignment will croak with an informative error message. If you specify a second parameter in your 'TYPE' attribute it will be treated as a CODE ref to be called when the assignment will fail.

All builtin types allow 'undef' or any false value as a valid value. Your own types (see section below) should probably do the same.

ROLLING YOUR OWN TYPES

NOTE: You do NOT have to roll your own type to just specify a blessed object - see the section above!

Specifying a CODE ref in your TYPE() attribute allows you to define your own types. Your function will be call with 1 parameter - the value that's about to be assigned to any variable of that TYPE().

Returning 1 (or any true value) will allow the assignment to happen. Return 0 (or any false value) will cause to assignment to croak.

I'm sure you can dream up of all sorts of interesting types - enumerated types, all sorts of specific string types, bounded numbers, words only from a specific language are the sorts of things that pop into my mind. Again I heartily expect you to surprise me with the types you come up with.

Note also you must allow for 'undef' as that is the initial value your variable will have! Allowing for any false value may also be a good idea.

FUNCTION RETURN VALUES

By specifying a TYPE() attribute for a function you 'lock-down' that function to only return that type.

If your function returns an array every element of that array must be of the specified type.

ROLL YOUR OWN ERROR FUNCTION

By default Variable::Strongly::Typed croaks when an assignment fails. You can change this behavior by supplying a code ref as a second parameter in your TYPE() attribute.

If you do this, your function will be called instead of 'croak' with 1 parameter, the value to be assigned to the variable that failed.

If your function does not 'croak' or 'die' the assignment will occur so be careful!

DIAGNOSTICS

croak'ed error messages for built-in types look like:

Cannot assign <value> to a [ scalar | hash | array ] 
  of type <whatever>

croak'ed error messages for user-supplied types look like:

Cannot assign <value> to a user-validated  
  [ scalar | hash | array ] variable

croak'ed error messages from an erroneous subroutine return value look like:

Cannot return <value> from a function or method of type
    <whatever>

If you'ved typed your subroutine & call it in a void context you'll get a croak like:

Throwing away return value of <whatever type it returns>

CONFIGURATION AND ENVIRONMENT

Variable::Strongly::Typed requires no configuration files or environment variables.

DEPENDENCIES

Attribute::Handlers handle the attribute stuff Class::Std::Utils handle the basic 'inside-out' module work Test::More for testing version for versioning

INCOMPATIBILITIES

None reported.

BUGS AND LIMITATIONS

No bugs have been reported.

Please report any bugs or feature requests to bug-perl-strongly-typed@rt.cpan.org, or through the web interface at http://rt.cpan.org.

SEE ALSO

Attributes::Types - The main differences are you can type subroutines with this monster and you can specify a different error handler other than the default of 'croak'. Oh the code is a hella cleaner also. Other than that these two modules are very similar.

AUTHOR

Mark Ethan Trostler <mark@zzo.com>

LICENCE AND COPYRIGHT

Copyright (c) 2005, Mark Ethan Trostler <mark@zzo.com>. All rights reserved.

This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See perlartistic.

DISCLAIMER OF WARRANTY

BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR CORRECTION.

IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.