multi getX(Foo $self:) returns Int {...} #const version
multi getX(Foo $self: is rw) returns Int is rw {...} #non-const version
If getX were called on a const Foo object then the first getX would be
called, and if it were called on a non-const Foo object the second one would
be.
Joe Gottman
> Will it be possible in perl6 to overload multis on the const-ness of a
> parameter, like C++ does? For instance,
>
> multi getX(Foo $self:) returns Int {...} #const version
> multi getX(Foo $self: is rw) returns Int is rw {...} #non-const version
That second one would have to be:
multi getX(Foo $self is rw:) returns Int is rw {...}
Then we have the issue that Perl 6 objects can't really be "constant",
since C<is constant> is a compile-time trait of *containers*...really just
a "don't assign to this container" marker.
However, within those limitations, I guess it's possible. After all, we have
to check for lvaluability of C<is rw> parameters anyway.
Damian
Might be one of those things that is taken as a tie-breaker, all other
things being equal. I'm thinking return types fall into the same category.
Larry
Speaking of multis and constants, Greg McCarroll wondered on IRC if
this would work:
multi factorial (Int 0) { 1 }
multi factorial (Int $n) { $n * factorial($n-1) }
Disregarding the fact that you should really write that as:
sub factorial (Int $n) {
my multi tail_fac ($result, 0) { $result }
my multi tail_fac ($result, $n) { tail_fac( $result * $n, $n - 1 ) }
tail_fac(1, $n);
}
(Assuming you want to do it recursively that is...)
--
Piers
How would I take a get a reference to the second one? I assume I could
get a reference to the first by
$ref = &getX(Foo);
Joe Gottman
Well, if there's overloading based on traits, siglets must support
traits. So, it would have to be:
$ref = &getX(Foo is rw:);
(The first would be)
$ref = &getX(Foo:);
Backwhacking those couldn't hurt, either.
Luke
> Speaking of multis and constants, Greg McCarroll wondered on IRC if
> this would work:
>
> multi factorial (Int 0) { 1 }
> multi factorial (Int $n) { $n * factorial($n-1) }
Probably not. We did discuss whether multimethods should be able to be
overloaded by value, but concluded (for that week, at least ;-) that this
might prove syntactically excessive.
Besides which, since multimethod dispatch will have to use C<isa> to determine
type compatibility on parameters anyway, it's trivial to implement this form
of value-based dispatch yourself:
class Zero {
multi *isa ($obj, Zero $class) { $obj ~~ 0 }
}
# and then...
multi factorial (Int&Zero $g) { 1 }
or, supposing we have some form of parameterized types, you could create
something more generic like:
class Val($N) {
multi *isa ($obj, Val($N) $class) { $obj ~~ $N }
}
# and then...
multi factorial (Int&Val(0) $g) { 1 }
;-)
Damian
Yes, YES! Marvelous!
Not that that couldn't be done with a closure anyway...
{
my Class %valClasses;
sub Val($N) returns Class {
my Class $rclass = %valClasses{$N} //= class {
multi *isa ($obj, $rclass $class) { $obj ~~ $N }
}
}
}
multi factorial (Int & Val(0) $g) { 1 }
Hmm, would Val(0) be evaluated at compile-time in that case... or must
I mark it with some sort of trait, or do some other kind of trick.
Cool, anyhow.
Luke
> Not that that couldn't be done with a closure anyway...
>
> {
> my Class %valClasses;
>
> sub Val($N) returns Class {
> my Class $rclass = %valClasses{$N} //= class {
> multi *isa ($obj, $rclass $class) { $obj ~~ $N }
> }
> }
> }
>
> multi factorial (Int & Val(0) $g) { 1 }
I don't think so. I seriously doubt you can put a run-time-evaluated sub call
in a type specification <visions of Dan fainting in horror> ;-)
A C<macro> might do the trick though.
Oh, and I was wrong to originally write: C<multi *isa ...>
Multimethods live in their own namespace. No * required.
Damian
Hey, I'm perfectly happy to delegate the entirety of sub dispatch to
someone else's code. That's fine with me. ;-P
--
Dan
--------------------------------------"it's like this"-------------------
Dan Sugalski even samurai
d...@sidhe.org have teddy bears and even
teddy bears get drunk
Sorry, you're not even wrong. :-)
: Multimethods live in their own namespace. No * required.
Alternately, we require the C<*> in order to accurately document
their scope. And I do think they live in C<*>. Otherwise we need to
come up with yet another name for the global scope that happens to
contain multimethods. An argument can also be made that we should
do that anyway on the grounds that we might someday have scoped
multi-methods of some kind or other.
I suppose can allow a C<sub *> in the same scope as C<multi *> for
the case that you want a global override of all the multimethods.
It just looks for the sub first. If that sub then wants to redispatch
to the multimethods, it'd have to use some special multimethod syntax
that doesn't look like a sub invocation, such as the notional
($a,$b,$c) forwhich foo()
we talked about in Sebastopol, however we end up spelling "forwhich".
It's really a kind of postpositional topicalizer for the following
predicate. English doesn't really have any good ones of those.
If I were Japanese, I'd spell it "wa" or "ga" or "no".
Well, okay, I'd actually spell it "は" or "が" or "の" if I were
*really* Japanese. :-)
Larry
For origin of the AUTOLOAD/DISPATCH stuff, see:
http://groups.google.com/groups?hl=en&selm=3E6E853D.9090604%40conway.org
Does this make sense as far as the "Rules of Dispatch”? I’ve included a
few suggestions where capability or sequence was unclear.
Given:
package pkg;
use Xclass qw(foo);
my $x = returns_an_Xclass();
foo $x; # Function-style
$x.foo; # Method-style
foo $x:; # Invocant-style (Is the colon needed?)
The dispatcher looks for:
(FM = Function-style or Method/Invocant-style, only)
##| FM Declaration Note
==+===========================================================
A1| my macro foo
A2| macro pkg::foo See note 0, below
A3| macro *foo
B-| Only for method, invocant styles.
B1| M submethod Xclass::DISPATCH May be at runtime
B2| M method Xclass::DISPATCH “
B3| M method SUPER::DISPATCH “ (SUPER meaning inherited)
C1| my sub DISPATCH
C2| sub pkg::DISPATCH
C3| sub *DISPATCH
D1| multi DISPATCH What's the signature required?
E1| my submethod foo Does this make sense?
E2| submethod pkg::foo Or this?
E3| submethod Xclass::foo Only method, invocant styles.
E4| submethod *foo See note 1, below.
F1| M my method|rule Xclass::foo See note 2, below.
F2| M my method|rule foo See note 2, below.
F3| M method|rule Xclass::foo
F4| M method|rule SUPER::foo (SUPER meaning inherited)
F5| M method|rule *foo See note 3, below.
G1| F my sub &foo See note 4, below.
G2| F sub pkg::foo
G3| F sub *foo
H1| my multi &foo See note 5.
H2| multi pkg::foo See note 5.
H3| multi *foo Requires compatible signature.
I1| M my submethod Xclass::AUTOLOAD
I2| M my method|rule Xclass::AUTOLOAD
I3| M submethod Xclass::AUTOLOAD
I4| M method Xclass::AUTOLOAD
J1| F? my sub AUTOLOAD
J2| F? sub pkg::AUTOLOAD
J3| F? sub *AUTOLOAD
K1| F? my multi AUTOLOAD See note 5.
K2| F? multi pkg::AUTOLOAD See note 5.
K3| F? multi *AUTOLOAD Requires compatible signature.
NOTES
=====
Note 0: macro pkg::foo -- There's no forward declaring macros, because
of the need to modify the behavior of the parser. But can macros be
package scoped? I assume yes, because the act of doing "use pkg;"
causes pkg to maybe get parsed, and if pkg defines macro foo, then
macro foo pollutes the namespace of the user if it doesn't have package
scope. From this, I assume that leaving and re-entering the package
scope should reactivate the macro. Is this also true?
pkg p1;
macro foo ...
pkg p2;
foo; # Doesn't invoke macro
pkg p1;
foo; # Invokes macro.
Note 1: submethod *foo -- Submethods are a little weird, since the
intent is (from A6) a non-inheritable method. Defining C<submethod
*foo> sort of implies defining a non-inheritable method for all objects
(which makes it essentially inherited, although things like SUPER won't
invoke it). This seems like the sort of bizarre, hideously dangerous
thing that was common in p4/5. Is it desired/supported? (I can think of
no use for it.)
Note 2: my method foo -- This is essentially "method with lexical
scope", which boggles my mind. But then it occurred to me that in the
right context (e.g. C<class X { my method foo()...}> this might be the
way to do submethods. Is it? Alternatively, is saying C<my method
Xclass::foo> a legal way to wrench control from the Xclass?
Note 3: method *foo -- This is speculation. A6 says, "Methods and
submethods are ordinarily package scoped". So I'm inclined to wonder
about extraordinary methods. Is this another useless cul-de-sac, or
does the design team have something concrete in mind here?
Note 4: subs named "foo", regardless of signature -- My interpretation
of subs is that there's no multidispatch once the name is matched.
Thus, if a sub with no signature exists in scope, it catches all calls
to that name. While if a sub with a signature exists in scope, it
catches calls to that name with matching signature. Some of Damian's
posts have seemed to me to imply that calls that don't match the
signature of the sub will FAIL, rather than dispatch on multimethods.
This needs clarification.
Note 5: my multi &foo -- Another clarification is needed. A6 says, 'You
can declare "scoped" subroutines by explicitly putting a my or our on
the front of the declaration'. The implication of the following
examples is of C<sub> declarations, strengthened by the explicit
mention of defining scoped macros using C<my>. But, in the interest of
being a pain in the neck, I figured I should request clarification: Can
I define a scoped multi? If so, how? If not, why not? (The "if not" is
somewhat important, given that a huge number of built-ins are going to
become multis. If I can't scope them, how about C<.wrap>ing them? Will
wrappers be scoped?)
Isn't this exactly what C<is cached> is for?
sub Val($N) is cached returns Class {
class {
multi *isa ($obj, $rclass $class) { $obj ~~ $N }
}
}
multi factorial (Int & Val(0) $g) { 1 }
(This is ignoring the fact that you can't use a runtime-evaluated sub in a
type declaration so the multi declaration wouldn't actually work.)
--
Trey Harris
Vice President
SAGE -- The System Administrators Guild (www.sage.org)
Opinions above are not necessarily those of SAGE.