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>; > > ... > > 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) { $x + $y } ... } And if you pretend that the Strs above were actually Ints, and that these Ints were actually Nums, then the semantics wouldn't work out right still. That kind of screams for a trait: sub process($x, $y) { my multi combine ($x, $y) is extended {...} my multi combine ... ... } And then it's pretty much the inverse of what we had before, plus an "is extended" trait. And so I don't think the naturalness argument gets us anywhere, except for the fact that we wouldn't have to define a trait. I guess I'm really arguing for masking by default instead of extention on the grounds of the principle of least surprise. I also like to think of names as concepts, such that if you're extending the concept, you ought to rename it. In that respect, lexically overriding multi variants instead of whole symbols at a time feels like lexically scoped classes automatically being derived from outer classes of the same name. And we all know that that is Just Wrong. Luke