Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@Juerd
Last active June 7, 2016 13:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Juerd/b6531810922d0cefec82b650be4915ca to your computer and use it in GitHub Desktop.
Save Juerd/b6531810922d0cefec82b650be4915ca to your computer and use it in GitHub Desktop.
Perl 6 types
Types are used as a way to organize behaviour and to guarantee that
certain constraints are enforced.
=head2 Value types
Although every value will invariably be of a single specific type,
behaviour can be shared among different types by means of
inheritance and composition. Type constraints can be applied to
variables, to limit which types of values a variable may hold.
A type name used as a function (i.e. by itself or with parentheses)
coerces the given value to that type. If no argument is given, it
results in the I<type object> for that type: a value that does have a
type, but does not have a value. It is said to be I<undefined>.
say Int.WHAT; # (Int)
say Int.defined; # False
say 42.WHAT; # (Int)
say 42.defined; # True
my $two-digits = Str(42);
my $type = Str;
say $type.defined; # False
my $three-digits = $type(123);
say $three-digits.WHAT; # (Str)
say $three-digits.defined; # True
Type constraints provide I<type safety>: only values of specific types
can be used. This can avoid bugs by checking that a variable is used in
the way that was intended. The optimizer can sometimes use the type
constraint to enable specialized, faster code execution. The nominal
type constraint of a variable can be given after the declarator (C<my>,
C<our>, C<has>, etc.) and before the name of the variable. Refinements
can be declared using C<where> and a value (e.g. a code block) to smart
match values against.
my Int $number;
say $number.WHAT; # (Int)
$number = 42;
$number = "forty-two"; # Type check failed
my Int $small-number where * < 100;
$small-number = 50;
$small-number = 99;
$small-number = 200; # Type check failed
A variable declaration without an explicit value assignment will
cause the variable to be initialized as the I<type object> of its
declared type.
my Int $number;
say $number.WHAT; # (Int)
say $number.defined; # False
$number = 42;
say $number.defined; # True
$number = Int;
say $number.defined; # False
The specific type refinement constraints of allowing only defined values
or only undefined values (that is, type objects), are specified by
appending C<:D> or C<:U> to the type name respectively.
my Int:D $number = 123;
$number = 42;
$number = Int; # Type check failed
my Any:U $type;
$type = Str;
$type = Int;
$type = 42; # Type check failed
The default type constraint for variable declarations is C<Mu>,
which will allow values of any type, but initializes as the C<Any>
type object. C<Any> inherits from C<Mu>, the root type, and as a
type constraint will not hold a C<Junction>.
my $foo;
my Mu $foo; # Same thing
say $foo.WHAT; # (Any)
$foo = 3 | 4;
say $foo.WHAT; # (Junction)
my Any $bar;
$bar = 3 | 4; # Type check failed
Type constraints for function arguments are similar, except the default
will be C<Any> instead of C<Mu>, making the parameter unable to hold
a C<Junction>. (If called with a junction, I<autothreading> will occur
instead.)
sub shout ($message, Int:D :$repetitions = 1) {
if ($message.defined) {
say $message.uc ~ "!" for 1 .. $repetitions;
} else {
say "THAT IS A TYPE OBJECT!" for 1 .. $repetitions;
}
}
shout Str; # THAT IS A TYPE OBJECT!
shout "Hello, world"; # HELLO, WORLD!
shout "Hello, world", :repetitions(3); # three times
shout "Hello, world", :repetitions(Int); # Type check failed
shout "Hello, world", :repetitions("three"); # Type check failed
shout "Hello" & "World";
# Would print either HELLO! WORLD! or WORLD! HELLO!, because
# execution order is not defined for autothreading.
=head3 Custom value types
...
=head2 Container types
...
@b2gills
Copy link

b2gills commented Jun 7, 2016

I think the docs should be using .^name when you just want the name, and leave .WHAT for more advanced usage.
( everywhere you have .WHAT you also have an invisible .gist because you are using say )
The only reason in my mind to use it here is if you do something like 42.WHAT =:= Int rather than 42 ~~ Int to say that it is exactly that type.

I would like to see at least a passing mention of roles somewhere, especially since you have a variable named $number that isn't Numeric, but is an Int.
( I think a book about Perl 6 best practices would tell you to type match against roles rather than classes in more places. )

These are just my first thoughts, and following them could result in something more difficult for new Perl 6 programmers, so feel free to ignore me if that is the case. I do like what you have here ignoring my pet peeves.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment