Categories
Posts in this category
- Introduction
- Strings, Arrays, Hashes;
- Types
- Basic Control Structures
- Subroutines and Signatures
- Objects and Classes
- Contexts
- Regexes (also called "rules")
- Junctions
- Comparing and Matching
- Containers and Values
- Where we are now - an update
- Changes to Perl 5 Operators
- Laziness
- Custom Operators
- The MAIN sub
- Twigils
- Enums
- Unicode
- Scoping
- Regexes strike back
- A grammar for (pseudo) XML
- Subset Types
- The State of the implementations
- Quoting and Parsing
- The Reduction Meta Operator
- The Cross Meta Operator
- Exceptions and control exceptions
- Common Perl 6 data processing idioms
- Currying
Sun, 07 Dec 2008
Subset Types
Permanent link
NAME
"Perl 5 to 6" Lesson 21 - Subset Types
SYNOPSIS
subset Squares of Real where { .sqrt.Int**2 == $_ };
multi sub square_root(Squares $x --> Int) {
return $x.sqrt.Int;
}
multi sub square_root(Real $x --> Real) {
return $x.sqrt;
}
DESCRIPTION
Java programmers tend to think of a type as either a class or an interface (which is something like a crippled class), but that view is too limited for Perl 6. A type is more generally a constraint of what a values a container can constraint. The "classical" constraint is it is an object of a class X or of a class that inherits from X. Perl 6 also has constraints like the class or the object does role Y, or this piece of code returns true for our object. The latter is the most general one, and is called a subset type:
subset Even of Int where { $_ % 2 == 0 }
# Even can now be used like every other type name
my Even $x = 2;
my Even $y = 3; # type mismatch error
(Try it out, Rakudo implements subset types).
You can also use anonymous subtypes in signatures:
sub foo (Int where { ... } $x) { ... }
# or with the variable at the front:
sub foo ($x of Int where { ... } ) { ... }
MOTIVATION
Allowing arbitrary type constraints in the form of code allows ultimate extensibility: if you don't like the current type system, you can just roll your own based on subset types.
It also makes libraries easier to extend: instead of dying on data that can't be handled, the subs and methods can simply declare their types in a way that "bad" data is rejected by the multi dispatcher. If somebody wants to handle data that the previous implementation rejected as "bad", he can simple add a multi sub with the same name that accepts the data. For example a math library that handles real numbers could be enhanced this way to also handle complex numbers.