RE: multi scoping

2005-09-05 Thread Thomas Sandlass
HaloO,

Luke wrote:

> Isn't the point of lexical scoping so that you don't have to worry
> whether somebody else called something the same thing you did?  I can
> picture this:
>
>multi combine (Any $x, Any $y) { ZCombinator.new($x, $y) }
>multi combine (@x, @y) { ZList.new([ @x, @y ]) }   # concat
>multi combine (Str $x, Str $y) { ZStr.new($x ~ $y) }

Ohh, is the bare multi special form now valid syntax?


> Clearly the author of process intended that two integers get added and
> anything else dies.  He was not aware of the combine defined many many
> lines above.   But he was smart and made his multis lexically scoped
> so he didn't have to worry.
> 
> Really, he should have written process like so:
>
>sub process($x, $y) { 
>my sub combine ($a, $b) {...}
>my multi combine (Any $a, Any $b) { die "Cannot combine" }
>my multi combine (Int $a, Int $b) { $a + $b }
>
>return combine($x, $y);
>}

Wouldn't using 'multi sub' allow to drop the first sub,
and override outer symbols 'combine' while a 'multi method'
would augment the inner view of future dispatches with the
inner targets?


> It seems fairly natural when we go with the extension mechanism that
> A12 seems to propose.  "multis extend, subs mask", so if you want to
> mask, you just define it as a sub first.  It's a little awkward, but
> it'll do.  The other way, however, is not nearly as natural:

I would interpret it as "methods are dispatched, subs are called" ---
and "slots are retrieved", but the latter is another subject...


># let's say that he wanted process() to do what I said he didn't intend
>sub process($x, $y) { 

This depends on his intentions to be inclusive or exclusive ;)


>my multi combine (Any $x, Any $y) { OUTER::combine($x, $y) }
>my multi combine (Int $x, Int $y) { $x + $y }
>...
>}

The combine(Int,Int) target as a method insures the closest match
for two Ints and the combine(Any,Any) insures the presence of a default.
But multi method targets "between" (Int,Int) and (Any,Any) are *not*
excluded, right?


> I guess I'm really arguing for masking by default instead of extention
> on the grounds of the principle of least surprise.

Me too, but with a different syntax by using either a Method or a Sub
type in the multi special form. Hmm, this immediately raises the question:
"Which form gets the default?". I guess it's undecidable in general and
thus a task for a pragma like 'use multi :sub' or some such.


> I also like to think of names as concepts, such that
> if you're extending the concept, you ought to rename it.

I disagree in so far as a concept like the open/close pair is
usefull for very different types of things. And as such these
perfect names shouldn't be blocked for ::Door just because they
are already used by ::IO. 

TSa






Re: multi scoping

2005-09-04 Thread Luke Palmer
On 9/4/05, Yuval Kogman <[EMAIL PROTECTED]> wrote:
> I always saw scoping of multis as something that applies to the
> variants...
> 
> multi sub foo {
> 
> }
> 
> {
> my multi sub foo {
> 
> }
> 
> # the second variant is just for this scope, but 
> neither masks
> # the other
> }

Reading over A12 again (in the section "Multiple Dispatch"), it
appears that you are right.

So let's figure out if that's actually the right way or the wrong way.
 I don't understand the second-to-last paragraph of that section,
which apparently explains why single variants mask.

> > You must explicitly ask for masking
> 
> I think this should be an option... You can either mask off a single
> variant by declaring one that overrides it in a tighter scope, with
> yadda yadda as the body, or you could ask a whole scope to be
> omitted from the possible variants.

Just to clarify, is this what you are suggesting?

multi foo (Int $x) { $x + 1 }
multi bar (Int $x) { $x + 1 } 
{
my sub foo ($x) {...}
my multi foo (Str $x) { "x" ~ $x }

my multi bar (Str $x) { "x" ~ $x }

bar("hi"); # xhi
bar(1);# 2
foo("hi"); # xhi
foo(1);# error, no compatible sub found
}

Though if that's the case, then it almost feels to me like the "multi"
should go before the "my".  But that would be screwing with the
consistency of the grammar a little too much, I think.

> > 2) Make multi automatically find the symbol that you would have
> > referred to if the definition had not been there, and add a multi case
> > to that symbol.  So in the example above, the innermost infix:<+> that
> > existed before you said "multi" was *infix:<+>, so the multi
> > definition would basically infer that you meant to say multi
> > *infix:<+> and do the right thing.
> 
> I don't agree with this... It takes the lexical scoping semantics
> out of things.

Oh, by the way, I was suggesting that a *bare* "multi" would do this. 
If you said "our" or "my", you are stating exactly what you mean. 
Well, almost (what does "my multi foo" mean if there is an outer
lexical multi foo -- mask or append?).

> There is one more problem though:
> 
> class Complex {
> multi sub &infix:<*> { ... }
> }
> 
> package Moose;
> use Complex;
> use SomeMathLib ;
> 
> ...
> 
> function($some_complex_number); # if function calls infix:<*> on
> # it's operand, somehow... What happens?

This is actually my *whole* problem, and the reason that I don't think
that variants should mask, but entire symbols should mask.  It seems
like you'd use a lexically scoped multi variant about as much as you'd
use a lexically scoped method on a class.  Can you think of a use for
that?

Isn't the point of lexical scoping so that you don't have to worry
whether somebody else called something the same thing you did?  I can
picture this:

multi combine (Any $x, Any $y) { ZCombinator.new($x, $y) }
multi combine (@x, @y) { ZList.new([ @x, @y ]) }   # concat
multi combine (Str $x, Str $y) { ZStr.new($x ~ $y) }

# ... many lines pass ...

sub process($x, $y) {
my multi combine (Any $a, Any $b) { die "Cannot combine" }
my multi combine (Int $a, Int $b) { $a + $b }

return combine($x, $y);
}

process("Foo", "Bar");
# Gets back a... what? ZStr?  What the heck is that

Clearly the author of process intended that two integers get added and
anything else dies.  He was not aware of the combine defined many many
lines above.   But he was smart and made his multis lexically scoped
so he didn't have to worry.

Really, he should have written process like so:

sub process($x, $y) { 
my sub combine ($a, $b) {...}
my multi combine (Any $a, Any $b) { die "Cannot combine" }
my multi combine (Int $a, Int $b) { $a + $b }

return combine($x, $y);
}

That case, to me, seems a lot more common than lexically overriding a
multi variant.  But I am open to counterexamples.

Assuming we have no information about the frequency, there is another
question to ask whether it makes sense to override or extend:  Is it
natural to do it both ways?  That is, does it feel right?  (Please,
get your mind out of the gutter and pay attention! :-)

It seems fairly natural when we go with the extension mechanism that
A12 seems to propose.  "multis extend, subs mask", so if you want to
mask, you just define it as a sub first.  It's a little awkward, but
it'll do.  The other way, however, is not nearly as natural:

# let's say that he wanted process() to do what I said he didn't intend
sub process($x, $y) { 
my multi combine (Any $x, Any $y) { OUTER::combine($x, $y) }
my multi combine (Int $x, Int $y) 

Re: multi scoping

2005-09-04 Thread Yuval Kogman
On Sun, Sep 04, 2005 at 07:55:21 +, Luke Palmer wrote:
> Here's a good Perl 6 final exam question:
> 
> Spot the mistake (hint: it's not in the math):
> 
> module Complex;
> 
> sub i() is export { 
> Complex.new(0,1)
> }
> multi sub infix:<+> (Complex $left, Complex $right) is export {
> Complex.new($left.real + $right.real, $left.imag + $right.imag);
> }
> multi sub infix:<*> (Complex $left, Complex $right) is export {
> Complex.new(
> $left.real * $right.real - $left.imag * $right.imag,
> $left.real * $right.imag + $right.real * $left.imag)
> }
> # ...
> 
> Give up?
> 
> When you add two complex numbers, you get into an infinite loop. 
> That's because infix:<+> adds things using the plus operator, which
> is, you guessed it, infix:<+>.  Now you'd think that multimethods
> would handle that, but they don't because by defining "multi sub
> infix:<+>" you are defining a *package* operator which *masks* the
> global operator!  So this turns into infinite recursion.

I always saw scoping of multis as something that applies to the
variants...

multi sub foo {

}

{
my multi sub foo {

}

# the second variant is just for this scope, but 
neither masks
# the other
}

> You must explicitly ask for masking

I think this should be an option... You can either mask off a single
variant by declaring one that overrides it in a tighter scope, with
yadda yadda as the body, or you could ask a whole scope to be
omitted from the possible variants.

> 2) Make multi automatically find the symbol that you would have
> referred to if the definition had not been there, and add a multi case
> to that symbol.  So in the example above, the innermost infix:<+> that
> existed before you said "multi" was *infix:<+>, so the multi
> definition would basically infer that you meant to say multi
> *infix:<+> and do the right thing.

I don't agree with this... It takes the lexical scoping semantics
out of things.

If multi's would cascade WRT to the scope of their definition, but
not mask, things should DWIM most of the time.

Please remember that when you declare a new multi you are usually
ammending to a commonly used operator, in order to extend it's
behavior in the scope that there is new data which much behave
accordingly.

There is one more problem though:

class Complex {
multi sub &infix:<*> { ... }
}

package Moose;
use Complex;
use SomeMathLib ;

...

function($some_complex_number); # if function calls infix:<*> on
# it's operand, somehow... What happens?

-- 
 ()  Yuval Kogman <[EMAIL PROTECTED]> 0xEBD27418  perl hacker &
 /\  kung foo master: /me spreads pj3Ar using 0wnage: neeyah!!!



pgpTDDK5o2dCa.pgp
Description: PGP signature