In a message dated Sat, 28 Oct 2006, Trey Harris writes:
In a message dated Sat, 28 Oct 2006, chromatic writes:
When you specify a type to constrain some operation, you specify that the
target entity must perform that role.
That statement is very concise and direct. If the fuzziness I observed about
the identity of the basic building block of type was unintentional, this
statement should be added to S06.
Incidentally, this would mean that a C<where> clause or junctive type
defines an anonymous role, and a type parameter defines a lexical role,
doesn't it? Seems like a useful characteristic of these constructs to
make explicit, perhaps in L<S12/Roles>.
I find this a little unintuitive given the way these typing particles are
used, though... If I were insane in a different way than I actually am, I
might think I could use this "every constraint is a role" behavior to
write:
sub pairs_up_to (Int $x where { $^x % 2 == 0 } ) {
(1..^$x:by(2)) >>=><< (2..$x:by(2))
}
pairs_up_to(4)}; # 1 => 2, 3 => 4
try { pairs_up_to(3) }
err say $!; # "No compatible subroutine found"
my $even_three = 3 but where { $_ % 2 == 0 }; # Huh?
try { pairs_up_to($even_three) }
err say $!; # What?
Not a useful example, I admit--which is why I had assumed C<where>
constraints were not roles, because I can't think of a useful example of
treating them as roles. But I suppose if you're determined to shoot
yourself in the foot like that, you'll find some way (like overloading
C<%> so it always returns 0).
You could probably even make Perl be able to call the sub in the second
C<try>, perhaps by making the anonymous roles generated by C<where> first
match by AST equivalence before testing their value against the constraint
or something.
Not that I think Perl should be able to do that... I'm just saying I
*might* think it would, given how roles usually work (and if I could come
up with a less contrived case, I might actually expect it to).
But *why* wouldn't it work? One of two reasons I think:
1. The first C<where> clause in the sub signature defines a different
anonymous role from the second C<where> clause after C<but>, even
though they're defined identically. In that case, $even_three would
have no practical difference from any other 3, because it merely mixes
in a role that never gets used.
2. The assignment would throw a mistyped value exception, just like
"my Num $foo = 'hi, mom'" does. (Except it doesn't. Should it? I
don't see a test that addresses this in the suite, nor something in
the Synopses to say that that assignment should fail.)
In either case, C<where> clauses create roles that values might do without
even realizing they're doing them, and which mutable objects might do and
then not do, willy-nilly, even in the course of the scope in which they
were typed to do it... which I think is new unless I just haven't been
paying attention.
sub saturate (Color $c where { $^c.saturation < 100 } ) {
$c.saturation = 100; # ???
correct_gama($c);
}
Did that mutation throw an exception, by changing $c's type to one it
can't have in this sub? If no, did we just lose gradual typing (assuming
correct_gamma cares)? Can we detect that, or do the roles created by
C<where> not participate in gradual typing? If C<where> constraints
weren't roles, this would make sense to me again.
It's duck-typing, but a very different type of duck typing than, say Ruby
has... it isn't a duck because it walks and quacks, but because when you
examine it with your particular duckish litmus test (your C<where>
clause), the litmus test turns the duckish color (Bool::True) you're
looking for.
A trifling issue, I guess, as you can just ignore how C<where> works so
long as it does work. But when I see a statement like "every X is really
syntactic sugar for a Y", I want to poke at all the X's to see how they
behave deeply as Y's.
Trey