Quick Tip #19: Build reusable data types

Perl 6 lets you constrain variable values with types, but you don’t have to limit yourself to the built-in types. Once defined, these act like the built-in types. Here are some subsets I’ve stolen from Brad Clawsie’s Subsets::Common module:

my package EXPORT::DEFAULT {
	...
	subset Pos of Numeric where * > 0;
	subset Neg of Numeric where * < 0;
	subset Zero of Numeric where * == 0;
	subset UNumeric of Numeric where * >= 0;

	subset Even of Int where * % 2 == 0;
	subset Odd  of Int where * % 2;

	subset Time::Hour12 of PosInt where * ~~ 1 .. 12;
	subset Time::Hour24 of Int    where * ~~ 0 .. 23;
	subset Time::Minute of Int    where * ~~ 0 .. 59;
	subset Time::Second of Int    where * ~~ 0 .. 59;
	...
}

The subset started the declaration and is followed by the name you want for the new type. This is a subset because you base it on an existing type that you declare with of. After that, you can use a where clause to refine your new type.

And, Brad put these in a package where he declared that everything is exported.

Here’s one that I created for my Perl 6 version of Chemistry::Elements. Don’t worry so much about what’s in the code; think more about the ability to have any code you need to decide if the value fits the constraint that you like. Here’s the type I defined to constrain an integer to a known atomic number (typically called Z from the German word Zahl, as in Atomzahl):

	subset ZInt of Cool is export where {
		state ( $min, $max ) = %names.keys.sort( { $^a <=> $^b } ).[0,*-1];
		( $_.truncate == $_ and $min <= $_ <= $max )
			or
		note "Expected a known atomic number between $min and $max, but got $_"
			and
		False;
		};

For my subset, I exported it by declaring it is export so other people using the module could use the type outside of my module. Most notably (heh), I can give a specific error message when the value doesn't match.

3 comments

  1. Since you can’t compare Complex numbers with = and the likes, I’d recommend to use Real instead of Numeric as the nominal type for Pos, Neg and so on.

Leave a Reply

Your email address will not be published. Required fields are marked *