In a message dated Thu, 29 Aug 2002, Damian Conway writes:

> And, of course, the C<is valued> property would smart-match its value
> against the corrresponding argument, so one could also code optimized
> variants like:
>
>       sub repeat is multi ($desc is valued(1),  &body) {
>           body(1);
>       }
>
>       sub repeat is multi ($desc is valued(0),  &body) {
>       }
>
>       sub repeat is multi ($desc is valued(['A'..'F']),  &body) {
>           die "Can't repeat hexadecimally";
>       }
>
> Come to think of it, maybe the property name probably should be C<is when>.

This is very nice.  But ordering of multimethod declarations suddenly
matters, doesn't it?  With simple multimethods based on class structures,
you use the best match (if the actual argument is Integer, I'll prefer the
method where the corresponding signature is Integer, then Rational, then
Real, then Complex), right?  But with this mechanism, you just have
boolean acceptance of the argument, so I assume that ordering will be how
you decide which multimethod to call--the first to accept its argument
wins.

If you want to define a new multimethod using the valued() property, ou're
left in a slightly awkward situation here--you can't install a multimethod
with a prior ordering to what's already been defined, can you?  So, if you
have something like the following:

  module Repeater {
    sub repeat is multi ($desc is valued(/\d+/), &body) {
    ...
    }
  }

  # In a later file

    sub Repeater::repeat is multi ($desc is valued(/\d*<[02468]>/), &body)
    { ... } # deal with even cases specially

That second sub would never get called, would it?

In general, though, I like it.  I've found myself making a lot of use
lately of the Virtual Constructor pattern, where you offer some free-form
data to a bunch of classes and they tell you which one can best
instantiate it, i.e.,

  sub createObject (*@data) {
    my @scores = for @.classes { $_.recognize(@data) but classOf($_)};
    my $bestClass = (sort byScore @scores)[0].classOf;
    return $bestClass.new(@data);
  }
  # Is my syntax right here?

A valued() property would obviate the common case where the recognition
scores are all boolean--I'd just have each class define a createObject
multimethod instead.  It would be kind of nice if the valued() property
could return a value, however.

> > I don't particularly like the old map and grep syntax.
>
> Recently someone suggested to me (sorry, whoever it was, my memory
> is still in anyother timezone) that, since C<given> returns a value:
>
>       $val = given $digit {
>               case [0..9]     { $_ }
>               case ['A'..'F'] { 10+ord($_)-ord('A') }
>               default         { undef }
>       };
>
> then maybe the other control structues should as well:
>
>       @squares = map { $_**2 } @nums;
>
>       @squares = for @nums { $_**2 };

This makes a lot of sense to me--notice I used it in my example above. :-)

> Of course, this example is trivially done with a hyperoperation:
>
>       @ squares = @nums ^** 2;
>
> But more complex examples could easily be constructed where even C<map>
> looks clunky and a list context C<for> would be a nice solution.
>
> It would also solve the problem of early escape:
>
>       @smallsquares = for @nums { last if $_ > 10; $_**2 };

Yes.  I think it works great as a C<map> replacement.  For a C<grep>
replacement, it's a little unwieldy:

P5:
   @odds = grep { $_ % 2 } @nums;

P6:
   @odds = for @nums { next unless $_ % 2; $_};

Trey

Reply via email to