Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

MMD as an object.

11 views
Skip to first unread message

Rod Adams

unread,
Mar 9, 2005, 1:54:30 AM3/9/05
to Perl6 Language List
It seems to me that there are several advantages to making a group of
multi with the same short name a single object, of type
MultiSub|MultiMethod, which internally holds references to the all the
various routines that share that short name.

It would behave like a tied sub (or method), with a .dispatch method to
decide which of the contained routines should be called this particular
time. Manhattan would be the default. However, one can override the
dispatch logic; implementing Luke's Patterns idea, for example.

This would also provide a relatively sane way to take a reference to a
single contained routine. I would expect a .matching method which takes
a list of types, and returns a reference to which routine would be
called given parameters of those types. Or one could get a reference to
the entire multi via C< my $ref = &multi; >. I don't think there has
been syntax introduced thus far that enables this ability. But it's
likely I missed it along the way, like I seem to be missing several
other things lately.

Another thing I haven't seen is how to declare a new multi at runtime.
Non-multi's can be created via C< &func := sub {...}; >, but that's
destructive to any other routines that might have occupied that
namespace. Using the object model, one could do this with C< &func.add(
sub {...}); >. There could also be a .delete method to remove a routine
already in the multi (give it a reference to uniquely identify it). Of
course, Luke would need to override the .add method to one that doesn't
throw errors when more than one routine with the same type signature is
thrown.

If this happens, I would expect that C< multi > would become a macro
which creates the multi of that short name if it doesn't already exist,
and then perform an .add to that multi.

There are likely several rough edges in here, and I've by no means
convinced myself that this is the Right Thing, but I thought I'd throw
the idea out there to what others thought of it.

-- Rod Adams.

Thomas Sandlaß

unread,
Mar 9, 2005, 6:26:42 AM3/9/05
to Rod Adams, Perl6 Language List
Rod Adams wrote:
> It seems to me that there are several advantages to making a group of
> multi with the same short name a single object, of type
> MultiSub|MultiMethod, which internally holds references to the all the
> various routines that share that short name.

It doesn't have to be junctive because for a multi it's irrelevant
if it's a method or a sub. This distinction is used only at compile
time of the class closure. So I guess there is a

class Multi is Code {...}

in Perl 6.


> It would behave like a tied sub (or method), with a .dispatch method to
> decide which of the contained routines should be called this particular
> time. Manhattan would be the default. However, one can override the
> dispatch logic; implementing Luke's Patterns idea, for example.

I see. Something like

use MMD::Manhattan;
use MMD::Symmetric;
use MMD::Pattern;
...

> [..] I don't think there has


> been syntax introduced thus far that enables this ability. But it's
> likely I missed it along the way, like I seem to be missing several
> other things lately.

I interpret the hash like syntax &foo<Int,Array[Int]> such that
&foo represents the complete set of branches of multi sub foo.
The only thing I wonder is this also supported for calling particular
subs without dispatching: foo<Int>(17)? Or even partial dispatching
on the sliced multi? This would BTW be something the optimizer would
use as well.


> Another thing I haven't seen is how to declare a new multi at runtime.
> Non-multi's can be created via C< &func := sub {...}; >, but that's
> destructive to any other routines that might have occupied that
> namespace.

If the above is correct than it would be more like hash assignment.


> There are likely several rough edges in here, and I've by no means
> convinced myself that this is the Right Thing, but I thought I'd throw
> the idea out there to what others thought of it.

I see some convergence and choices where that is not the case.


MfG
--
TSa (Thomas Sandlaß)


Rod Adams

unread,
Mar 9, 2005, 7:19:25 AM3/9/05
to Perl6 Language List
Thomas Sandlaß wrote:

> Rod Adams wrote:
>
>> It seems to me that there are several advantages to making a group of
>> multi with the same short name a single object, of type
>> MultiSub|MultiMethod, which internally holds references to the all
>> the various routines that share that short name.
>
>
> It doesn't have to be junctive because for a multi it's irrelevant
> if it's a method or a sub. This distinction is used only at compile
> time of the class closure. So I guess there is a
>
> class Multi is Code {...}
>
> in Perl 6.

I wasn't intending it to be junctive. I was just noting that you needed
separate holders for subs and methods, since you shouldn't be able to
stuff a method into a multi sub.

>
>> It would behave like a tied sub (or method), with a .dispatch method
>> to decide which of the contained routines should be called this
>> particular time. Manhattan would be the default. However, one can
>> override the dispatch logic; implementing Luke's Patterns idea, for
>> example.
>
>
> I see. Something like
>
> use MMD::Manhattan;
> use MMD::Symmetric;
> use MMD::Pattern;
> ...

I was thinking more along the lines of :

use MMD::Pattern;

our &func is MMD::Pattern;

multi func (...) {...}
multi func (... ...) {...}
multi func (... ... ...) {...}

multi func2 (...) {...}
multi func2 (... ...) {...}
multi func2 (... ... ...) {...}

Where &func would get Pattern MMD, and func2 would get Manhattan MMD.


-- Rod Adams

Luke Palmer

unread,
Mar 9, 2005, 10:58:07 AM3/9/05
to Rod Adams, Perl6 Language List
Rod Adams writes:
> I wasn't intending it to be junctive. I was just noting that you needed
> separate holders for subs and methods, since you shouldn't be able to
> stuff a method into a multi sub.

Keep in mind that the two following definitions are equivalent:

class A { method foo () {...} }
multi sub foo (A $a) {...}

I think stuffing a method into a multi sub should be just fine.

Luke

Thomas Sandlaß

unread,
Mar 9, 2005, 12:21:17 PM3/9/05
to Perl6 Language List
Luke Palmer wrote:
> Keep in mind that the two following definitions are equivalent:
>
> class A { method foo () {...} }
> multi sub foo (A $a) {...}

Except for attribute access, I think.
For public attrs the accessor is not used and private ones are available:

class A
{
has $.pub = "pub";
has $:priv = "priv";
method foo ()
{
say "pub = $.pub";
say "priv = $:priv";
}
}

multi sub foo( A $a )
{
say "pub = $a.pub()";
}

Another subtlety is that the method call syntax prefers single dispatch:

my $obj = A.new;

$obj.foo();
foo( $obj );


> I think stuffing a method into a multi sub should be just fine.

Me too. The above is irrelevant for the call site.

Larry Wall

unread,
Mar 9, 2005, 2:07:22 PM3/9/05
to Perl6 Language List
On Wed, Mar 09, 2005 at 06:19:25AM -0600, Rod Adams wrote:
: I was thinking more along the lines of :

:
: use MMD::Pattern;
:
: our &func is MMD::Pattern;
:
: multi func (...) {...}
: multi func (... ...) {...}
: multi func (... ... ...) {...}
:
: multi func2 (...) {...}
: multi func2 (... ...) {...}
: multi func2 (... ... ...) {...}
:
: Where &func would get Pattern MMD, and func2 would get Manhattan MMD.

Might be better to define some modifiers other than "multi" just for the
documentation value, if you're going to have different policies in the
same file like that. I expect that's a rarity, though. Most files
would have a single MMD policy.

But the main problem I see with all this is that MMD is supposedly
combining short names from potentially many different scopes across
*multiple* files, and what do you do if those have different policies?
Plus the OP assumed that all instances of a particular short name are
represented by a single object, which is not necessarily the case,
since different lexical scopes can see different (and potentially
overlapping) sets of multis with the same short name. I suppose one
could get around that by placing an implicit constraint on multis
you're not supposed to be able to see, though. Except that you really
need unique long names as well within one of these objects, and two
completely distinct lexical scopes could have long names that would
be confused with each other. Oh wait, the lexical scope constraint
would be part of the long name, just like any other constraint.
Nevermind. Though maybe you still want to have separate objects
since it's a performance hit to actually evaluate constraints at
run time.

But we still have the problem of conflicting policies in different
scopes. Maybe it's not a problem if we view different policies as just
different ways of marking autogenerated signatures with distance, if
we can come up with a single underlying *scalar* distance measure that
different policies can map multidimensional distances to differently.
Some policies might only choose between 0 and Inf for the scalar
distance, for instance, while others might try to finesse additional
distance values. It seems to me that both the manhattan scheme and
the pure scheme can be subsumed under that, but I could be wrong.

Larry

Rod Adams

unread,
Mar 9, 2005, 4:38:52 PM3/9/05
to Perl6 Language List
Larry Wall wrote:

>On Wed, Mar 09, 2005 at 06:19:25AM -0600, Rod Adams wrote:
>: I was thinking more along the lines of :
>:
>: use MMD::Pattern;
>:
>: our &func is MMD::Pattern;
>:
>: multi func (...) {...}
>: multi func (... ...) {...}
>: multi func (... ... ...) {...}
>:
>: multi func2 (...) {...}
>: multi func2 (... ...) {...}
>: multi func2 (... ... ...) {...}
>:
>: Where &func would get Pattern MMD, and func2 would get Manhattan MMD.
>
>Might be better to define some modifiers other than "multi" just for the
>documentation value, if you're going to have different policies in the
>same file like that. I expect that's a rarity, though. Most files
>would have a single MMD policy.
>
>

Well, my intent was that one should be assigning the policy to a given
multi, not a given scope. If people wish to change the default policy
for multis defined in a given scope, I have no problems with that.

The reason for binding the policy to a given multi was so people could
write a package Foo with a pack of multi sub bar's, using policy
MMD::Random, and export into a different scope, but still have the
caller use the Random policy when calling bar.

>But the main problem I see with all this is that MMD is supposedly
>combining short names from potentially many different scopes across
>*multiple* files, and what do you do if those have different policies?
>Plus the OP assumed that all instances of a particular short name are
>represented by a single object, which is not necessarily the case,
>since different lexical scopes can see different (and potentially
>overlapping) sets of multis with the same short name. I suppose one
>could get around that by placing an implicit constraint on multis
>you're not supposed to be able to see, though. Except that you really
>need unique long names as well within one of these objects, and two
>completely distinct lexical scopes could have long names that would
>be confused with each other. Oh wait, the lexical scope constraint
>would be part of the long name, just like any other constraint.
>Nevermind. Though maybe you still want to have separate objects
>since it's a performance hit to actually evaluate constraints at
>run time.
>

I'm going to interpret this as "This is a solvable problem that just
needs a little optimization in the compiler."
Please correct me if this a poor interpretation.

>But we still have the problem of conflicting policies in different
>scopes. Maybe it's not a problem if we view different policies as just
>different ways of marking autogenerated signatures with distance, if
>we can come up with a single underlying *scalar* distance measure that
>different policies can map multidimensional distances to differently.
>Some policies might only choose between 0 and Inf for the scalar
>distance, for instance, while others might try to finesse additional
>distance values. It seems to me that both the manhattan scheme and
>the pure scheme can be subsumed under that, but I could be wrong.
>
>

The problem with this is that it requires people to be very cooperative
with how they assign their scalar values. And that feels like asking for
trouble.

I think a better solution is to make it where a given short name can
only have one policy. Trying to assign two policies to the same multi
would be a warning at least, and preferably an error.

There lingers the case of:

use Foo; # from above, exports &bar is MMD::Random

multi sub bar {...}

Does this generate an error, since one could expect this particular &bar
to be Manhattan? Or does it assume Random, since there's already a &bar
in existence? In my head, it currently makes sense to say that the new
&bar inherits the Random policy. Only something like:

use Foo;
our &bar is MMD::Manhattan;

multi sub bar {...}

Would trigger an error.


-- Rod Adams

Miroslav Silovic

unread,
Mar 10, 2005, 4:42:31 AM3/10/05
to r...@rodadams.net, perl6-l...@perl.org
r...@rodadams.net wrote:

> It would behave like a tied sub (or method), with a .dispatch method
> to decide which of the contained routines should be called this
> particular time. Manhattan would be the default. However, one can
> override the dispatch logic; implementing Luke's Patterns idea, for
> example.
>

Hmm, that ties into my wishlist item. Would it be possible to implement
method combinators (or rather, multimethod combinators) from Common LISP
in addition to this? The only CLOS feature that A12 doesn't mention,
can't let that happen. ;)

class A { ... }
class B is A { ... }

1> multi foo ($a) is before { ... }
2> multi foo (B $a) { ... next METHOD; ...}
3> multi foo (A $a) { ... }
4> multi foo ($a) is after { ... }
5> multi foo ($a) is around { ... next METHOD; }
6> multi foo ($a) is before { ... }

.... and this runs all 5 methods, in order 5 > 1 > 2 > 6 > 3 > (returns
to 2) > 4 > (returns to 5)
And yes, 6 and 1 do have the same signature. The rule is to run all
before methods in order of the currently selected distance (ties broken
in random order ;) ), and all after methods in the reverse order.

Oh, and the reason why around methods are useful?

multi foo ($a) is around {
CATCH { ... }
next METHOD;
}

Note that this catches the exceptions thrown by any version of foo, even
though at this point you don't know whether foo will be specialised.
before methods aren't useful for this since their stack frame and
handler blocks don't linger during the executions of other methods.

Common LISP references:

Standard method combination (before, after, around)
http://www.lispworks.com/documentation/HyperSpec/Body/07_ffb.htm

Other method combinations (+, and, etc)
http://www.lispworks.com/documentation/HyperSpec/Body/07_ffd.htm

Creating your own method combinations (define-method-combination)
http://www.lispworks.com/documentation/HyperSpec/Body/m_defi_4.htm

Come to think of this, it seems that the only thing that'd need to be
modified to accomodate both Rod's and mine proposal is to move CALLONE
and CALLALL from the class to be MMD object somehow. Perhaps

multi CALLONE ($obj, $method where { $_ == &func }, *@_) { ... }

Hmm, but this syntax strikes me as icky.

Miro

David Storrs

unread,
Mar 10, 2005, 8:00:22 AM3/10/05
to Perl6 Language List
On Wed, Mar 09, 2005 at 03:38:52PM -0600, Rod Adams wrote:

> There lingers the case of:
>
> use Foo; # from above, exports &bar is MMD::Random
>
> multi sub bar {...}
>
> Does this generate an error, since one could expect this particular &bar
> to be Manhattan? Or does it assume Random, since there's already a &bar
> in existence? In my head, it currently makes sense to say that the new
> &bar inherits the Random policy. Only something like:

This seems like action-at-a-distance to me; I use some random module,
define a couple of multis without realizing that they also exist in
the module, and am baffled as to why I don't get the dispatch behavior
I expect.

--Dks

Rod Adams

unread,
Mar 10, 2005, 3:22:20 PM3/10/05
to Perl6 Language List
David Storrs wrote:

Well, if you were not expecting Foo to export some &bar's, then you're
in for a surprise regardless of dispatch when you call &bar in your code
and one of Foo::bar gets called instead of one of yours, because it was
a closer match.

I would say that people should know what they are getting into when they
C< use > something. In Perl 6, that use could "conviently" swap the
meanings of all the + and - signs, and not say a word. In my head, this
extends to knowing what it exports, and if there's anything weird about it.

If I am consciously adding more multi's into something a package
provided, to extend it's functionality, I would think that keeping the
original dispatch system would make sense. Otherwise the imported
methods could fail to work properly.

-- Rod Adams


Rod Adams

unread,
Mar 10, 2005, 4:28:13 PM3/10/05
to l...@toetsch.at, perl6-i...@perl.org, perl6-l...@perl.org
Leopold Toetsch wrote:

>Rod Adams <r...@rodadams.net> wrote:
>
>
>>It seems to me that there are several advantages to making a group of
>>multi with the same short name a single object, of type
>>MultiSub|MultiMethod, which internally holds references to the all the
>>various routines that share that short name.
>>
>>
>

>Discussion seems to have went off into esoteric cases of locally
>overriden dispatcher policies and what not.
>
>
I don't think it's as esoteric as you might think. Consider:

package Foo;

use MMD::Random;
our &bar is MMD::Random is export(DEFAULT);

multi sub bar ($x) {...};
multi sub bar ($x) {...};
multi sub bar ($x) {...};

==========

use Foo;

multi sub bar ($x) {...};

Note that they all have the same signature. The Manhattan policy would
complain about this, since it's looking for the closest parameter match.
The Random policy does not care. It's going to randomly pick any member
method for each call.

So what we then fall into is the problem of which policy is in effect
for a given multi can affect what's in scope at a given point. If the
later file included:

sub baz {
my multi sub bar ($x) {...};

bar(5);
}

A Manhattan policy would have the local bar mask the package bar with
the same signature. A Random policy would temporarily add it into the mix.


Since the main goal of treating multis as an object was to be able to
override the dispatch policy, I think how a user defined policy
interacts with different localities is very much on topic.

>What I'd like to know is more basic things:
>
>1) is there a MultiSub object with one short name that holds all
>possible long names (and function references)?
>
>
As for whether such a thing is visible at the Perl level, I think that
depends on if we allow user defined dispatch policies or not. If not,
it's just an introspection tool that could be addressed in other ways.

Even without custom policies, p6c may decide to go the MultiSub object
route at the compiler level. But I can't speak to that, nor on the
Compiler <-> Parrot interaction.

>What about multi subs? They can be defined everywhere. Given:
>
> multi sub *foo(A $a, B $b) {...}
>
>Is this something like:
>
> %globals{"foo"} --> MultiSub{"foo_A_B" => Sub, ...}
>
>What about a not so global multi:
>
> multi sub foo(A $a, B $b) {...}
>
>
This can be seen as questioning how to keep track of what multi's are in
scope at any given point in time, because you must dispatch amongst all
the multi's visible, regardless of the differing scope. Method dispatch
has a similar issue with hunting down all the C< isa >s for possible
method's to include in dispatch. So far, I think this issue has been
politely ignored as p6c's problem, not p6l's.

However if you have multi's from a mix of different sources and scopes,
all with the same short name, which policy decides how to dispatch
amongst them at a given calling locality is very much at issue, and is
roughly where we are in the discussion.

>Thanks for clarifying,
>
>
Sorry I couldn't clarify more.


-- Rod Adams

David Storrs

unread,
Mar 10, 2005, 8:40:31 PM3/10/05
to Perl6 Language List
On Thu, Mar 10, 2005 at 02:22:20PM -0600, Rod Adams wrote:
> David Storrs wrote:
> >On Wed, Mar 09, 2005 at 03:38:52PM -0600, Rod Adams wrote:
> >> use Foo; # from above, exports &bar is MMD::Random
> >> multi sub bar {...}
> >>
> >>Does this generate an error, since one could expect this particular &bar
> >>to be Manhattan? Or does it assume Random, since there's already a &bar
> >>in existence?
> >
> >This seems like action-at-a-distance to me;
> >
> Well, if you were not expecting Foo to export some &bar's, then you're
> in for a surprise regardless of dispatch when you call &bar in your code
> and one of Foo::bar gets called instead of one of yours, because it was
> a closer match.
>
> I would say that people should know what they are getting into when they
> C< use > something.


What I'm hearing you say here is "Yes, it's action-at-a-distance, but
it's your job to make sure it doesn't trip you up." The problem that
I see is that I may well be able to keep track of everything from the
modules I import, but what about the ones THEY import...and the ones
THEY import...and so on. In a medium-to-large software project, that
can get to be a lot of modules, very quickly.

--Dks

Rod Adams

unread,
Mar 10, 2005, 10:27:45 PM3/10/05
to Perl6 Language List
David Storrs wrote:

The question is not what they import. The question is what they export
into your package. If it's not exported into your package, the other
multi's are in a different package, and get a different short name. I
see the short name as including the package name for subs, class name
for methods. Only the signature is chopped off.

I'm only asking you to keep track of what gets imported into your
current package, which I do not think is asking for too much, even in a
large scale project. Whatever your used modules have in their packages
which they keep to themselves, including everything _they_ imported from
_other_ modules, is not your concern... that's a different package space.

If you go pumping new multi's into someone else's package by saying C<
multi sub Foo::Bar {...} >, well, you better be familiar with what's
already there.

So, it could be considered action at a distance, but feels more like
keeping track of what you've asked others to dump in your lap.

-- Rod Adams

Rod Adams

unread,
Mar 11, 2005, 7:55:55 AM3/11/05
to l...@toetsch.at, perl6-l...@perl.org
Leopold Toetsch wrote:

>Ok. If you'd really need such random dispatch, it could be done like
>this, when I interpret A12 correctly:
>
> sub run_random_bar($x) {
> my @meths = WALKMETH($x, :method('bar'));
> my $meth = @meths[rand(@meths.elems)];
> $meth($x);
> }
>
>or even with
>
> my sub bar($x) {...} # same body as above
>
> bar($x);
>
>If you need an esoteric dispatcher roll your own :)
>
>
That's certainly the doable with any language that provides sufficient
introspection, within limits. It's a matter of where you store your hand
rolled dispatcher.

If I were to need a different policy for a given method .bar, I would
likely create something called .bar much like your "run_random_bar",
which then dispatches amongst methods I name something like ._bar .

I see some detractions to this approach:
1) Users wishing to add another multi to the mix must know that they
have to make it a ._bar instead of a .bar. This is a relatively minor
concern. It feels rather clumsy having two different names for what is
essentially a single set of multis.

2) What parameter signature do you give the wrapper method, so it does
not clobber the arguments, yet still has them to pass on to the
appropriate method? And at the same time, determine what signature the
wrapper was called with, to determine who to dispatch to... I hadn't
said it before, but I had assumed the dispatch method of the MultiSub
would have a signature of something like "Str @types" passed to it.

3) It does not allow more than one sub with the same signature and short
name to be in scope at the same time. There are cases more legitimate
than MMD::Random for this. For instance, dispatching based on return
type. Or off of some user defined trait the different methods have. Or
the most common case: on named arguments.

My understanding of the P6 Long Names is that if one creates a multi
with the same parameter signature as a previously defined multi of same
short name, it masks the previous one if in a tighter scope, or erases
the previous if the same scope.

The original thought was to have the policy take over the acceptance of
new multi's into the MultiSub as well as taking over dispatch, thus
allowing for such flexibilities.


>>Since the main goal of treating multis as an object was to be able to
>>override the dispatch policy, I think how a user defined policy
>>interacts with different localities is very much on topic.
>>
>>
>

>I don't think that the policy should be in the MultiSub object.
>
I'm not sure if I think it should be there either. It just seemed to
allow some flexibility in having it there that is otherwise very
difficult to do.

And quite likely, the policy itself would not be in the MultiSub, but
the MultiSub would have a reference to which policy it's using.

>Your approach would very likely disable all possible optimizations.
>
>
It's always been in the back of my head that this would be a performance
hit. How big of one I don't have a good feel for. I've been attempting
to get a feel for how much is gained in return for that hit. So far I am
inclined to agree that the benefits do not outweigh the costs, but I
like to know exactly what I'm giving up when making those decisions.

>>>1) is there a MultiSub object with one short name that holds all
>>>possible long names (and function references)?
>>>
>>>
>>As for whether such a thing is visible at the Perl level, I think that
>>depends on if we allow user defined dispatch policies or not. If not,
>>it's just an introspection tool that could be addressed in other ways.
>>
>>
>

>Don't think so. It's a problem of namespaces and how these multi subs
>are managed. It touches Perl6 as well as Parrot.
>
>
What I meant to say was that yes, there does need to be management and
introspection capabilities at the Perl6 level, but they do not *require*
it to be a MultiSub object to happen. Some non-object solution could
likely be found.

With that mindset, the compiler could use a PMC object for it, but show
the Language something else, or it could show the Language something
that looks like an object, but use something different in Parrot. Those
are questions I am not able to answer.

Some of the management issues I see that need addressing are:

- How do I dynamically create a new multi with differing levels of
scope? For instance, add a package scoped multi from inside a sub of
that package?

- If I'm in a lexical scope which overrides a certain long name, how can
I call the package scoped version of that long name instead?

- Given a method returned from WALKMETH, what scope level is it defined at?

- Can I get a CODEREF that points to the short name as a whole, or do I
have to take a ref to a given multi?

- How can I tell if a given long name already exists?

>
>
>>>What about multi subs? They can be defined everywhere. Given:
>>>
>>> multi sub *foo(A $a, B $b) {...}
>>>
>>>Is this something like:
>>>
>>> %globals{"foo"} --> MultiSub{"foo_A_B" => Sub, ...}
>>>
>>>What about a not so global multi:
>>>
>>> multi sub foo(A $a, B $b) {...}
>>>
>>>
>>>
>>>
>>This can be seen as questioning how to keep track of what multi's are in
>>scope at any given point in time, because you must dispatch amongst all
>>the multi's visible, regardless of the differing scope.
>>
>>
>

>Sure. But the dispatch scheme is described in A12. That is per se not
>the problem.
>
>
Unless your proposal was to allow user defined changing of that scheme.
Then it becomes a problem.


-- Rod Adams

PS - I stopped the cross posting to p6i, since I was asking more
questions than answering, and those question didn't belong there.

Leopold Toetsch

unread,
Mar 11, 2005, 9:09:41 AM3/11/05
to Rod Adams, perl6-l...@perl.org
Rod Adams <r...@rodadams.net> wrote:

> If I were to need a different policy for a given method .bar, I would
> likely create something called .bar much like your "run_random_bar",
> which then dispatches amongst methods I name something like ._bar .

> I see some detractions to this approach:
> 1) Users wishing to add another multi to the mix must know that they
> have to make it a ._bar instead of a .bar.

Not necessarily, AFAIK. You can define a lexical "sub bar", which hides
all outer multi subs. This "bar" can be used to dispatch to the multi
subs.

> 2) What parameter signature do you give the wrapper method, so it does
> not clobber the arguments, yet still has them to pass on to the
> appropriate method? And at the same time, determine what signature the
> wrapper was called with, to determine who to dispatch to...

Well, I presume, if you are writing such code, i.e. a bunch of mutli
subs with the same signature, you are very well aware of what you are
doing. So you'll know, how you call the dispatcher (and what funny
effects you'll yield :)

>... I hadn't
> said it before, but I had assumed the dispatch method of the MultiSub
> would have a signature of something like "Str @types" passed to it.

I don't thing that the MultiSub does dispatch nor that it has a dispatch
method. The MultiSub object is just a collection of multi Sub candidates
for one of the scopes [lexical, package/module/class, global, builtin].

The current dispatcher has to collect a list of possible candidates from
all the possible multis, and then decide, depending on the policy, which
sub should actually be called.

> 3) It does not allow more than one sub with the same signature and short
> name to be in scope at the same time.

That's mainly a Perl6 compiler problem. When the MultiSub is just a list
of candidates, you can append whatever signature you like. There is no
check for duplicates. It's only the dispatcher that will detect
ambiguous signatures, if it cares about, like the default dispatcher.

> ... For instance, dispatching based on return
> type.

Well, while there is a symmetry in call and return, when Parrot is
concerned, dispatching on return types isn't easy, or better, it could
just be done for the total static case, where all return results are
known beforehand. For that case you could just call different subs in
the first case.
If the return type is just the runtime result, after the sub is run, you
can do nothing in the dispatcher, which long before had called the sub.

> ... Or off of some user defined trait the different methods have. Or


> the most common case: on named arguments.

A trait creates usually an anonymous subclass of the involved class and
therefore has precedence over a not so specific class.

MMD on named arguments isn't specified yet, or:

,--[ A12 ]----------------------------------------------------------------
| It is not likely that Perl 6.0.0 will support multiple dispatch on named
| arguments,
`-------------------------------------------------------------------------

> My understanding of the P6 Long Names is that if one creates a multi
> with the same parameter signature as a previously defined multi of same
> short name, it masks the previous one if in a tighter scope, or erases
> the previous if the same scope.

As said, that's mainly a Perl6 compiler problem. The compiler can't emit
two identical "long names" as one of these wouldn't be callabale then.

> The original thought was to have the policy take over the acceptance of
> new multi's into the MultiSub as well as taking over dispatch, thus
> allowing for such flexibilities.

What policy is in effect, if you define somewhere a "multi sub"? I
think, that can't work.

> And quite likely, the policy itself would not be in the MultiSub, but
> the MultiSub would have a reference to which policy it's using.

No, I don't think so. The current (lexical) scope has the policy,
according to A12.

> Some of the management issues I see that need addressing are:

[ good questions for the compiler folks ]

leo

Rod Adams

unread,
Mar 11, 2005, 3:55:06 PM3/11/05
to perl6-l...@perl.org
Leopold Toetsch wrote:

>Rod Adams <r...@rodadams.net> wrote:
>
>
>>If I were to need a different policy for a given method .bar, I would
>>likely create something called .bar much like your "run_random_bar",
>>which then dispatches amongst methods I name something like ._bar .
>>
>>
>>I see some detractions to this approach:
>>1) Users wishing to add another multi to the mix must know that they
>>have to make it a ._bar instead of a .bar.
>>
>>
>Not necessarily, AFAIK. You can define a lexical "sub bar", which hides
>all outer multi subs. This "bar" can be used to dispatch to the multi
>subs.
>
>

I sounds like a good plan, as long as it works. However, I'd want to
create the "sub" at the same scope (most likely class/package) as the
"multi sub"s with the same name. I'm presently not clear if that's
allowable. If I have to create a lexical method in each user to dispatch
to my class, that seems sub optimal. I prefer to stick with .bar vs ._bar

>>2) What parameter signature do you give the wrapper method, so it does
>>not clobber the arguments, yet still has them to pass on to the
>>appropriate method? And at the same time, determine what signature the
>>wrapper was called with, to determine who to dispatch to...
>>
>>
>
>Well, I presume, if you are writing such code, i.e. a bunch of mutli
>subs with the same signature, you are very well aware of what you are
>doing. So you'll know, how you call the dispatcher (and what funny
>effects you'll yield :)
>
>

Consider the case where I wish to create several multi's with
significantly different signatures, but you write each one twice, once
with an "is debug" trait, and once with an "is operational" trait. I
would have some runtime signal to determine if I need to be running the
debug versions, or the operational versions.

If you put too much onus on the caller function to get the call correct,
you might as well just name all the methods something different and
forget about MMD altogether.

>>... I hadn't
>>said it before, but I had assumed the dispatch method of the MultiSub
>>would have a signature of something like "Str @types" passed to it.
>>
>>
>
>I don't thing that the MultiSub does dispatch nor that it has a dispatch
>method. The MultiSub object is just a collection of multi Sub candidates
>for one of the scopes [lexical, package/module/class, global, builtin].
>
>

Currently you are likely correct. I was proposing to change that.

>The current dispatcher has to collect a list of possible candidates from
>all the possible multis, and then decide, depending on the policy, which
>sub should actually be called.
>
>

I was offering the ability to change which policy does the decisions,
after collecting the candidates.

>>3) It does not allow more than one sub with the same signature and short
>>name to be in scope at the same time.
>>
>>
>
>That's mainly a Perl6 compiler problem. When the MultiSub is just a list
>of candidates, you can append whatever signature you like. There is no
>check for duplicates. It's only the dispatcher that will detect
>ambiguous signatures, if it cares about, like the default dispatcher.
>
>

So you're saying that if I create a multi with the same scope and long
name as a preexisting multi, that old multi will still be around in
memory, even though it could never be called without a custom dispatcher?

I was under the impression that defining two multi's with the same long
name in the same scope clobbered one of the involved parties and
triggered a redefinition warning.

>>... For instance, dispatching based on return
>>type.
>>
>>
>
>Well, while there is a symmetry in call and return, when Parrot is
>concerned, dispatching on return types isn't easy, or better, it could
>just be done for the total static case, where all return results are
>known beforehand. For that case you could just call different subs in
>the first case.
>
>

I was imagining dispatching based off the C< want > function, which I
have no idea how it will be implemented at the Parrot level, but it's a
defined part of Perl.

>If the return type is just the runtime result, after the sub is run, you
>can do nothing in the dispatcher, which long before had called the sub.
>
>

Of course.

>
>
>>... Or off of some user defined trait the different methods have. Or
>>the most common case: on named arguments.
>>
>>
>
>A trait creates usually an anonymous subclass of the involved class and
>therefore has precedence over a not so specific class.
>
>

A trait added to an object instance creates an anonymous subclass,
certainly.
But I didn't think that adding a trait to a member of a class created a
new subclass...

>MMD on named arguments isn't specified yet, or:
>
>,--[ A12 ]----------------------------------------------------------------
>| It is not likely that Perl 6.0.0 will support multiple dispatch on named
>| arguments,
>`-------------------------------------------------------------------------
>
>

Indeed, that is the current case.

>>My understanding of the P6 Long Names is that if one creates a multi
>>with the same parameter signature as a previously defined multi of same
>>short name, it masks the previous one if in a tighter scope, or erases
>>the previous if the same scope.
>>
>>
>
>As said, that's mainly a Perl6 compiler problem. The compiler can't emit
>two identical "long names" as one of these wouldn't be callabale then.
>
>

But it's a language issue as to whether we want the compiler to allow
two identical "long names" or not.

>>The original thought was to have the policy take over the acceptance of
>>new multi's into the MultiSub as well as taking over dispatch, thus
>>allowing for such flexibilities.
>>
>>
>
>What policy is in effect, if you define somewhere a "multi sub"? I
>think, that can't work.
>
>

If a MultiSub with that short name already exists, you follow it's
policy. If not, you create a new MultiSub with whatever policy is
default to the current scope.

=========

Overall, I've come to the following conclusion:

- We are sacrificing some capabilities by not having user defined MMD.
- However, the utility of those capabilities does not merit the effort
it would take to implement in 6.0.
- We should, however, leave the door open for 6.x to allow such things
with as little pain as possible.

So I'm dropping this thread.

-- Rod Adams

0 new messages