On Sat, Dec 20, 2003 at 12:41:10PM -0800, Jonathan Lang wrote:
: So what happens if more than one of the candidates is tagged as the
: default?  The same thing as if none of them was?  This could happen if
: both Predator and Pet have declared their 'feed' methods as the default.  

Could blow up, or look for a more generic default that isn't in a tie.
The latter seems more fail-soft, since something else of the same name
is likelier to know what to do than some random exception handler in
who-knows-what dynamic context.

: > Arguably, the role's might be required to declare their methods "multi"
: > if they want to participate in this, but that's one of those things
: > that feel like they ought to be declared by the user rather than the
: > definer.  On the other hand, maybe a role would feel that its method
: > *must* be unique, and leaving out the "multi" is the way to do that.
: > But I hate to get into the trap of culturally requiring every method
: > in every role to specify "multi".  It's a little too much like the C++
: > ubiquitous-const problem.
: 
: What about making multi dispatches the assumed behavior, with a C<unique>
: keyword to explicitly shut it off (for the sake of optimization)?  That
: is, replace the C<multi> keyword used to define routines that participate
: in multiple dispatching with a C<unique> keyword used to define routines
: that don't.  

Now that's...an *interesting* idea.  Maybe even worth some punctuation
right there in the name.  Maybe "is unique" is written:

    my sub print! ([EMAIL PROTECTED]) {...}

meaning: "Always call this one, dang it!"

Then maybe "is default" could be

    my sub print? ([EMAIL PROTECTED]) {...}

meaning: "Call this one in case of a tie?"

The character would only be in the declaration, not in the call.
(Of course, that prevents us from actually using those characters in
names like Ruby does, but I'm not sure that's a big loss.)

But I'm getting sidetracked.  The underlying question is whether "multi"
should be the default.  And that's still an interesting idea regardless
of the syntax.

Another unexplored question is how and whether to open up multiple
dispatch to more scopes than just the first one in which you find
the name, which is the normal Perl6 semantics.  I doubt looking
everywhere should be the default, but just as a class might call any
or all of its roles' methods, a lexically scoped sub might want to
call or dispatch to any set of subs of that name that are visible in
the current scope.  Naming such collections is an interesting problem.
Taking scope transitions into account in the distance calculation of
multi signatures could be even more interesting.  If you define your
own multi foo, and there's a global multi foo, how far away is that?
Is it worth a level of inheritance in one of the arguments?  Is it
worth more?  Less?  Is it worth anything, if you've included both
in your set of possible multis to begin with?

[Should probably change the Subject if you want reply to this one.
In fact, I should probably have split this message into separate
responses...]

: > Where that may cause problems if you want to inherit from an existing 
: > trait that does something else wicked.  But then, traits aren't often 
: > going to be inherited anyway, since their purpose is to break the 
: > rules.  
: 
: Unless you're trying to create a variation on an existing trait, of
: course.  

Which might well be done with wrappers rather than via inheritance.  I
don't think traits are going to have a lot of methods you'd want to
inherit.

On the other hand, applying a container type to a container is currently
done with C<is>, and one might very well want to inherit from a container
type, which (like Perl 5 tie classes) might have oodles of inheritable
methods.  But then, C<is> isn't ambiguous because you're not using it
on a class at that point, so maybe it's still okay...

: > We can maybe inherit from classof(trait) to get around any difficulties.
: 
: Perhaps you could use C<type> instead of C<classof>?  More concise and
: just as meaningful.  

Unless C<type> encompasses roles and subtypes but C<classof> doesn't...
Still, if you're using C<type> on a "real" object, it has to be a class.

Probably ought to be C<typeof> if we want to reserve C<type> for a
declarator keyword.  Though if we end up with typed refs, we could
well end up with a situation where classof($self) returns DangerousPet
but typeof($self) returns Predator.

: > So I'm still thinking we do inheritance with "is" rather than "isa".
: > We just have to keep our names straight.  Generally, traits will
: > be lowercase, and true class or role names start with an uppercase
: > letter.
: 
: But then, this remains merely a convention; a sloppy programmer (or one
: who isn't worried about his code being extensible) could violate it
: without the compiler complaining.  

Certainly.

: The only fear that I have here is whether we're violating the "different
: things should look different" principle: are traits and superclasses
: similar enough to each other to be added to a class by the same means?  It
: might not be a bad idea to include "isa" as a more explicit alternative to
: "is", with the added benefit that "isa traitname" would be short for "is
: classof(traitname)".

That's a possibility.

: It also occurs to me that traits can be thought of
: as adjectives (thus the "is <trait>" vs. "is a <class>" distinction) -
: another way to attach an adjective to a noun in English is to prepend it
: to the noun: 
: 
:   my Dog $Spot is red; 
:   my black Cat $Tom; 
:   my thoughtful $Larry is overworked; 
: 
: where red, black, thoughtful, and overworked are traits.  
: 
: Or is this too much?  

It's not too much for English.  :-)

But it is a little confusing in Perl because people might think
$Larry returns things of type "thoughtful", rather than thoughtful
being applied to the container type.  And

    my black Cat $Tom; 

would be taken to mean something like:

    my $Tom returns (Cat is black); 

rather than

    my $Tom is black returns Cat; 

Maybe that's okay, but we haven't really talked about applying traits
to classes outside of declarations, and what that would denote.

: In a similar vein, what about making a disjunction of classes in an C<is>
: or C<isa> clause synonymous with a sequence of appropriate clauses?  Ditto
: with traits and C<is>, roles and C<does>, attributes and C<has>, etc.;
: thus: 
: 
:   class DangerousPet does Pet & Predator {
:   }
: 
: would be the same as
: 
:   class DangerousPet does Pet does Predator {
:   }

Depends on how you look at it.  A DangerousPet is something that can
act like either a Pet or a Predator, or both.  Sometimes you want &
and sometimes you want |.  (Of course, a lawyer will tell you that
"and" and "or" mean the same thing in a legal document.)  I suppose
there could even be some sense in

    class DangerousPet does Pet ^ Predator {
    }

meaning it can be a Pet or a Predator but not both at the same time.
Of course, that probably means that you can't actually have any
objects of type DangerousPet.  Or maybe it does, but you can't call
any ambiguous DangerousPet methods without casting to either Pet or
Predator.  Hmm...

That would mean that C<does> implies a constraint test on typeof($self)
rather than classof($self).  (Presuming typed refs in the first place,
of course.)

Larry

Reply via email to