http://www.perlmonks.org?node_id=329797


in reply to Class::Multimethods namespace collusion

The correct solution to this problem is to enhance Class::Multimethods to handle it correctly. ;-)

The problem boils down to the fact that the first argument passed to any Perl 5 constructor is the name of the class on which the constructor was called.

So, in effect, every constructor multimethod has to have '$' as the type specifier for its first parameter. Which leaves no way to tell them apart.

But there's no reason that a multiple dispatch system has to restrict itself to considering just the types of the arguments on which it's dispatching. An obvious extension is to allow the dispatcher to examine the values of those parameters and differentiate on that basis too.

Suppose, for example, that we were to generalize Class::Multimethods so that parameters could also be specified as a subroutine. When such a variant was considered in the dispatch process, instead of working out the inheritance distance from the argument's class to the parameter class, Class::Multimethods would pass the argument to the subroutine, and use the sub's return value as the distance (with undef indicating type incompatibility).

Then one could set up subroutine generators for just about any kind of dispatch criterion. For example:

sub Value_eq { my ($target_value) = @_; sub { $_[0] eq $target_value ? 0 : undef } } sub Negative { sub { $_[0] < 0 ? 0 : undef } }

Then we would be able to code class constructors as multimethods, like so:

package Base; multimethod new => (Value_eq('Base')) => sub {...} multimethod new => (Value_eq('Base'), Negative) => sub {...} multimethod new => (Value_eq('Base'), '#') => sub {...} package Der; use base 'Base'; multimethod new => (Value_eq('Der')) => sub {...} multimethod new => (Value_eq('Der'), '$') => sub {...} # etc.

Of course, we could simplify that even further by providing a subroutine generator that specifically compared argument values against the name of the current class:

sub This::Class { my $target_value = caller; sub { $_[0] eq $target_value ? 0 : undef } }

With which we could code multiply dispatched constructors like so:

package Base; multimethod new => (This::Class) => sub {...} multimethod new => (This::Class, Negative) => sub {...} multimethod new => (This::Class, '#') => sub {...} package Der; use base 'Base'; multimethod new => (This::Class) => sub {...} multimethod new => (This::Class, '$') => sub {...} # etc.

Now, if only I had the tuits to actually make Class::Multimethods work that way! :-(

Ah well...at least I can put it at the top of the module's ToDo list.

Damian

Replies are listed 'Best First'.
Re: Re: Class::Multimethods namespace collusion
by bakunin (Scribe) on Feb 18, 2004 at 10:03 UTC
    Thank you very much!! I hope this node will be very enlightening for those who use Class::Multimethods.