On 2009-Oct-17, at 1:55 am, Jon Lang wrote:
This implies that both Logging and Math do Numeric, since the
invocant ought to be of a type that the class does.
I would expect that
role Logging { method log(Numeric $x:) {...} }
means the invocant is really of type Numeric & Logging, without
Logging having to do Numeric. On the other hand, I can see that
strictly that might not make sense, so perhaps I really do need to
create a compound NumLog type first, so I can have method log(NumLog:)?
Or can I create a method outside of any role:
role Numeric {...}
role Logging {...}
method log(Numeric Logging $x:) {...}
(of course, that might be implicitly creating an anonymous compound
type for me...)
I think that what you're actually looking for (for the purpose of
illustration) is Logging::log:(Numeric $x:) and Numeric::log:
(Numeric $x:).
Oh, yes!
If $x does Numeric and $x does Logging, then it has a class that has
already encountered the potential conflict and resolved it in some
way. For example:
class Baz does Numeric does Logging {
method log(Numeric $x:) {$x.Numeric::log;}
method log(Logging $x:) {$x.Logging::log;}
} #`<Baz postpones the decision until it knows which role it's
being asked to play: Numeric or Logging.>
Baz illustrates my proposal: if $x is a Baz, it will need to check
the context to see if it's supposed to be acting like a Numeric or
like a Logging, and will act accordingly - or it will complain about
ambiguity if it can't figure out which role to play. And the
definition for Baz works because Logging does Numeric.
I suppose given that I want Logging's method log(Numeric Logging:)
rather than its log(Any Logging:), the second method there should
really be:
method log(Numeric Logging $x:) {$x.Logging::log;}
You cannot define a class that does Logging and does Numeric without
defining at least one log method, because they conflict; and a class
must somehow resolve all such conflicts.
OK; although it seems reasonable to have some sugar for the obvious
kind of "keep them all" methods like in this example. In fact, we
probably have that already, by declaring a "proto log" that makes the
others all work according to their sigs. And my mistake was thinking
that you could have the same sig doing different things, but really
the second sig is log(Numeric Logging:).
(The only way to have the same sig twice would be something like if
Logging defined a special version of log() for Numeric objects, while
Numeric defined a special log() for Logging objects -- but
semantically that ought to mean the same thing in both cases, so we do
want a single method to handle that.)
In the Baz case, it addresses the matter by making two options
available according to the role being played: Numeric or Logging.
All you have to do then is to somehow indicate which role is being
played.
If you can't tell by the routine's signature, my own preference
would be to make it explicit by means of a "given" block:
given Logging $x { .log } # logs like a Logging
given Numeric $x { .log } # logs like a Numeric
I also thought "given" sounded good for this, but it would have to
work differently from a normal "given": if $x doesn't do Logging, then
it needs to skip the block. (Also, it looks very close to casting:
"given Logging($x)". Maybe something a bit more visually distinctive
would be helpful, something like "given $x as Logging", etc.?)
But I could see other alternatives:
.log given Logging $x; # assumes the inclusion of a "given"
statement modifier.
I think "given", as either a modifier or a block, is the "prettiest"
syntax.
$x -> Numeric $n { ... ; $n.log ; ... }
What I like about this is using a sig to apply the context, so no new
syntax is needed.
(But I'll suggest something new for -> in general: what if "$x ->
Numeric" with no "$n" variable were shorthand for "$x -> Numeric $x is
rw", i.e. a shorthand that used the same variable name inside the
block as the one being passed in? That would be useful in cases like
this where we don't particularly want to rename $x.)
$x.log:(Logging:);
And I like this way because it's the most compact, "inline" way to
indicate it.
-David