Luke Palmer wrote:
> Well, "multi" is no longer a declarator in its own right, but rather a
> modifier. Synopsis & Exegesis 6 show this.
I don't know about Exegesis 6, but Synopsis 6
(http://dev.perl.org/perl6/synopsis/S06.html) is still showing multi to be
a declarator on par with sub, method, rule, and macro.
> I think this makes things even clearer, and has a fine-grained but
> elegant control over the "scope" of the routine.
Agreed; I'd like something like this to be implemented.
> This easily allows for "multisubmethods" and even "multimacros"
> (provided you have yourself a polymorphic object at compile time).
For the record, subs never have invocants as currently described - so you
could easily say that any sub that has an invocant is actually a
submethod:
sub touch ($a: $b) {...}
would be synonymous with:
submethod touch ($a: $b) {...}
> I also think it's important to say "multi" explicitly every time you
> mean it. It allows the compiler to warn you when you're just being
> stupid about scoping as opposed to actually wanting to overload the
> routine. From a design perspective, it makes it clear that this method
> introduces logical control-flow in addition to performing a task.
That's probably good programming advice; but it should remain advice
rather than being a requirement.
If you allow the distinction between a method and a multimethod to be
determined implicitly, you can, if you choose, ignore the "submethod" and
"multi" keywords altogether with minimal loss of capabilities:
submethod touch ($a) {...}
multi watch ($a, $b) {...}
would be equivelent to
sub touch ($_: $a) {...}
method watch ($a, $b:) {...}
=====
Jonathan "Dataweaver" Lang
__________________________________
Do you Yahoo!?
Protect your identity with Yahoo! Mail AddressGuard
http://antispam.yahoo.com/whatsnewfree
Then you should probably read it. It is the most recent of the
documents, so what it says is closest to the current thinking. Plus,
it's a fun read.
> but Synopsis 6 (http://dev.perl.org/perl6/synopsis/S06.html) is still
> showing multi to be a declarator on par with sub, method, rule, and
> macro.
Now that I look, yes, that's true. It's wrong.
> > I think this makes things even clearer, and has a fine-grained but
> > elegant control over the "scope" of the routine.
>
> Agreed; I'd like something like this to be implemented.
>
> > This easily allows for "multisubmethods" and even "multimacros"
> > (provided you have yourself a polymorphic object at compile time).
>
> For the record, subs never have invocants as currently described - so you
> could easily say that any sub that has an invocant is actually a
> submethod:
>
> sub touch ($a: $b) {...}
>
> would be synonymous with:
>
> submethod touch ($a: $b) {...}
Hmm. Well, that depends on whether calling works like it does in Perl
5. That is, given:
multi sub touch (Foo $a: $b) {...}
Is this legal:
my $x = new Foo;
$x.touch;
I haven't been able to deduce this.
> > I also think it's important to say "multi" explicitly every time you
> > mean it. It allows the compiler to warn you when you're just being
> > stupid about scoping as opposed to actually wanting to overload the
> > routine. From a design perspective, it makes it clear that this method
> > introduces logical control-flow in addition to performing a task.
>
> That's probably good programming advice; but it should remain advice
> rather than being a requirement.
Spoken like a true Perl programmer :-)
I don't see the win in losing the C<multi> keyword though. Sure, there
are 5 fewer characters, but declarations aren't a place where concise
and terse are synonymous. IMO, a colon is too small a character for
such a large distinction. Misunderstanding the rule slightly can lead
to overriding instead of overloading... reminds me of C++ [1].
> If you allow the distinction between a method and a multimethod to be
> determined implicitly, you can, if you choose, ignore the "submethod" and
> "multi" keywords altogether with minimal loss of capabilities:
>
> submethod touch ($a) {...}
> multi watch ($a, $b) {...}
>
> would be equivelent to
>
> sub touch ($_: $a) {...}
> method watch ($a, $b:) {...}
Luke
[1] While I haven't the hatred for C++ that quite a few people on this
list do, I definitely consider it an "advanced" language, by which I
mean there are subtle variants in the rules that cause wildy different
behaviors. Beginners (and intermediates) still struggle with this one:
class Base {
public:
virtual int num() const { return 10; }
}
class Derived : public Base {
public:
int num() { return 20; }
}
int main() {
Base* b = new Base; Base* d = new Derived;
cout << b->num() << endl; // 10
cout << d->num() << endl; // 10 !!
}
Now why the heck did the call to d->num() return 10??!!! Because they
missed a C<const> in the overriding of num(), hiding it instead. This
is precisely what would happen if you missed a colon in adding a
multimethod. Sorry, I don't want to inflict this kind of pain on Perl
programmers.
OK; I just finished it. Apparently, there's a distinction between
"multimethod" and "multi sub", and it's a distinction which renders one of
my points invalid. A multimethod has multiple invocants and handles
dispatching based on the types of said invocants. A "multi sub" has no
invocants; instead, it has a subset of its parameters (seperated from the
others by a colon) which it uses for dispatching purposes. As such,
"multi sub ($a: $b) {...}" already has meaning, in that dispatching will
be decided strictly off of $a's type.
So the following three declarations cover very similar (but not quite
identical) things:
multi sub call ($a: $b) {...}
submethod invoke ($a: $b) {...}
method check ($a: $b) {...}
All three of these use multiple dispatching. The only distinctions are
that "invoke" and "check" can be called using method-like syntax, whereas
"call" cannot; and "check" pays attention to inheritence, whereas "call"
and "invoke" do not.
In the case of multiple "dispatch variables", the situation gets a bit
messier as I understand you:
multi sub call ($a, $b: $c) {...}
multi submethod invoke ($a, $b: $c) {...}
multi method check ($a, $b: $c) {...}
Why do we suddenly need to append the "multi" keyword to "submethod" and
"method"? Because it has a different meaning for method or submethod:
with "sub", the "multi" keyword means "use multiple dispatching", and so
we use it any time that we have one or more "dispatch parameters"; with
"submethod" and "method", multiple dispatching is assumed and the keyword
means "use more than one invocant".
IMHO, we should choose one of these definitions for "multi" and stick with
it. If you go with "use multiple dispatching", multi becomes redundant
for method and submethod; if you go with "allow more than one dispatch
parameter", then you ought to be able to declare a multiply dispatching
sub with a single dispatch parameter without using the multi keyword.
Personally, I think that the first definition is the less confusing one.
If you choose it, you'll never have need to use the "multi" keyword in
conjunction with "method" or "submethod", restricting its use in practice
to cases where multiple dispatching doesn't normally occur (subs and
macros, mostly). In those cases, one _could_ implicitly determine whether
the sub or function is multiply dispatched by looking for the colon in the
signature; but I tend to agree in these cases that requiring the "multi"
keyword might be a good idea.
> multi sub call ($a, $b: $c) {...}
> multi submethod invoke ($a, $b: $c) {...}
> multi method check ($a, $b: $c) {...}
>
> Why do we suddenly need to append the "multi" keyword to "submethod" and
> "method"?
So the compiler knows we really did mean for that (sub)method to be multiply
dispatched, and didn't just accidentally put the colon in the wrong place.
> with "submethod" and "method", multiple dispatching is assumed
No. Regular (sub)methods are singly dispatched.
Damian
In other words, what a name means in a given scope is a kind of
invariant--there's no magic hocus pocus in which multimethod dispatch
suddenly "steals" calls from ordinary method dispatch.
This is actually more powerful than the usual multimethods. To get
the usual behavior of multimethods in other languages, you have to
explicitly declare the multimethods in global space:
multi sub *add( Foo $foo, Bar $bar );
If you write:
multi sub add( Foo $foo, Bar $bar );
then the current package has multiple add routines, but they aren't global.
If you write:
multi my sub add( Foo $foo, Bar $bar );
then the current *lexical* scope has multiple add routines!
If you write:
multi method add( $self: Foo $foo, Bar $bar );
then there are multiple add methods in the current class. Note the
invocant is not optional in this case. Also, there's an implied
second colon after $bar, indicating the end of the arguments to be
considered for multi dispatch. (You can put as many colons as you
want in any multi declaration--each subsequent colon indicates that
the preceding additional argument or arguments are to be used as
"tie breakers, just as Foo and Bar are being used for tie-breaking
in the method above.) Likewise for submethods:
multi submethod add( $self: Foo $foo, Bar $bar );
In essence, the compiler could implement "multi" by taking any such
set of identically named routines and implementing them as a single
routine with switching logic to tell the types apart.
One ramification of all this is that "true" multimethods must always
be called as subroutines, not as methods.
I hope this clarifies things a bit. Well, more than a bit...
Larry
Also, I assume that invoke and check will have access to $a's private
data members and methods, while call will not.
Joe Gottman
So what is the, ahem, submethod for determining the dispatch within the
tie-breaking cascades? A simple sum of differences? Cartesian
distance?
Luke
> Larry