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

Reply via email to