In a Decorator/delegation context, it seems like yet another case where
there's two ways to do things:
1- In(tro)spect the classes you want to replicate/extend and determine their
signature. Then 'eval' code that declares every single element of the
signature, usually just calling a helper function and then passing along the
call.
2- Use AUTOMETH[DEF] to implement a single point of code that catches the
method calls, handles whatever Expectations or Delegations exist, then
passes along the call:
AUTOMETHDEF {
return {
check_expectations();
check_preconditions();
call();
check_postconditions();
};
}
The benefits of option 2 is no 'eval', more straightforward code, etc.
The big drawback is that once you've extended a class in this fashion,
there's no knowing what your class' interface looks like from the outside.
How, then, would I go about specifying my 'intented' interface?
That is, I want to handle all or part of the interface via a switching
method like AUTOLOAD, but I want to let everyone inspect my class from
without and determine the actual supported method names, signatures, etc.
A12 is not clear on this point: it mentions (teasingly) AUTOMETH and
AUTOMETHDEF, but doesn't go into specifics.
From A12: `Perl 6's version of .meta.can returns a "WALK"
iterator for a set of routines that match the name.
`... it [.meta.can] will exclude from the list of
candidates any class that defines its own AUTOMETH
method, on the assumption that each such AUTOMETH
method has already had its chance to add any callable
names to the list. If the class's AUTOMETH wishes to
supply a method, it should return a reference to that
method.´
From this, I infer that .meth.can (and dispatchery in general) will traverse
the class/role network looking for methods that match the request.
Apparently the AUTOMETH code will be invoked to determine what code matches
a request. AUTOMETH will "return a reference to" a matching method. This
implies that AUTOMETH is expected to resolve dispatch within the class --
"Here is the best answer I know."
This seems an awkward way to implement dispatch, since the price of using
AUTOMETH is being able to write a method dispatcher -- there won't be many
one-line AUTHMETH methods.
Also, it precludes having multiple candidates from a single source -- like
most "playoff" systems (but not the BCS :-).
Given that we've got a signature mechanism, it should be straightforward to
"declare" to dynwhat methods a class/role will respond. Thus, instead of a
interviewing a network of classes, the dispatcher could collect the data and
massage it in an appropriate fashion.
This has the side-benefit of solving my problem nicely: I can "declare" the
names to which I will respond, so that in(tro)spection will produce the
desired result, and so that invalid calls to my class can be caught before
being dispatched -- either at compile time or earlier in the runtime cycle.
(Even if they are only caught at runtime, they will at least be caught by
Perl itself rather than falling out the bottom of my switch statement.)
Comment?
=Austin
No, the intent of AUTOMETH is merely to indicate that the name might
be resolved by this class somehow. But I see your point that not
all dispatchers want a single answer. The discussion of AUTOMETH
was written primarily with single dispatch in mind, but it would be
pretty easy to generalize AUTOMETH to return a list of candidates if
the "name" in question is wildcardish in some fashion.
: This seems an awkward way to implement dispatch, since the price of using
: AUTOMETH is being able to write a method dispatcher -- there won't be many
: one-line AUTHMETH methods.
:
: Also, it precludes having multiple candidates from a single source -- like
: most "playoff" systems (but not the BCS :-).
:
: Given that we've got a signature mechanism, it should be straightforward to
: "declare" to dynwhat methods a class/role will respond. Thus, instead of a
: interviewing a network of classes, the dispatcher could collect the data and
: massage it in an appropriate fashion.
I don't see how that's terribly different from what A12 is feebly
attempting to say. It's all very well to supply dynamic declaration,
but if you don't have a logical time to call it, it doesn't do you much
good. AUTOMETH is designed to be called at dispatch time, when you
already have a spec for the method you want to call. The only earlier
dynamic time to declare methods that makes much sense to me is class
composition time, and we have other mechanisms for declaring methods
at that time.
: This has the side-benefit of solving my problem nicely: I can "declare" the
: names to which I will respond, so that in(tro)spection will produce the
: desired result, and so that invalid calls to my class can be caught before
: being dispatched -- either at compile time or earlier in the runtime cycle.
: (Even if they are only caught at runtime, they will at least be caught by
: Perl itself rather than falling out the bottom of my switch statement.)
:
: Comment?
I think you might be missing the fact that the reference (or
references, for multimethod dispatch) returned by AUTOMETH is not
necessarily a reference to a defined method. It will often be
a reference to a stub that is later resolved by an AUTOMETHDEF or
a delegation. You need the method stub anyway to hold the properties
on which your metadata is predicated. Except for performance reasons,
it would be silly for the class to store method metadata redundantly
when it can just keep a list of the method objects themselves,
whether or not those method objects are defined or merely declared.
On the other hand, it could simply be that I don't understand what
you're asking for. Stranger things have happened...
Larry
I agree: classes have a chance to pre-specify the class
signatures, and objects get a chance to dynamically agree to
undertake method calls.
The timeframe I was thinking of was object construction time.
>
> : This has the side-benefit of solving my problem nicely: I can
> : "declare" the names to which I will respond, so that in(tro)
> : spection will produce the desired result, and so that invalid
> : calls to my class can be caught before being dispatched --
> : either at compile time or earlier in the runtime cycle.
> : (Even if they are only caught at runtime, they will at least
> : be caught by Perl itself rather than falling out the bottom
> : of my switch statement.)
> :
> : Comment?
>
> I think you might be missing the fact that the reference (or
> references, for multimethod dispatch) returned by AUTOMETH is
> not necessarily a reference to a defined method. It will
> often be a reference to a stub that is later resolved by an
> AUTOMETHDEF or a delegation. You need the method stub anyway
> to hold the properties on which your metadata is predicated.
> Except for performance reasons, it would be silly for the
> class to store method metadata redundantly when it can just
> keep a list of the method objects themselves, whether or not
> those method objects are defined or merely declared.
I'm not sure what the "metadata" would be, but I don't think
I missed anything regarding the characteristics of the reference
returned by AUTOMETH -- I had assumed that AUTOMETH returned
what was needed to continue execution.
>
> On the other hand, it could simply be that I don't understand
> what you're asking for. Stranger things have happened...
What I'm looking for is a concrete class signature.
That is, I want an external entity to be able to inspect the
class, or an object of the class, and KNOW what methods are
supported.
If the coder wants to implement everything via AUTOMETH and not
tell me, that's okay.
But if I was told what methods a class supports, I want to be able
to manufacture a proxy for that class that supports the same
methods, maybe a few more mixed in, and will report that concrete
signature when inspected:
4x:
class Dog {
method bark {...}
method grow {...}
method scratch {...}
method sniff {...}
method walk {...}
method hunt {...}
}
class prOxyGen
{
role proxy {...}
method new($what)
{
$class = get_class($what);
$proxy = new MetaClass($class.name);
$proxy.does(proxy);
for $class.meta.methods() -> $method {
$proxy.add_method($method)
unless $method ~~ 'hunt';
}
return $proxy;
}
}
If I say:
my Dog $spot = new Dog('Spot');
my $gettysburg_address = new prOxyGen($spot);
I want to be able to query $spot and get a list of public methods.
I want to be able to query $rover and get a similar list.
I *do not* want the signature for the proxy class to look like
"stuff added by the proxy role, plus AUTOMETH".
> Larry
=Austin
I don't see the value of that. The class isn't going to be interested
in storing separate metadata for each object. If the object stores
it itself then you might as well resolve it at dispatch time.
: What I'm looking for is a concrete class signature.
:
: That is, I want an external entity to be able to inspect the
: class, or an object of the class, and KNOW what methods are
: supported.
That is what AUTOMETH supplies in the general case. I'm sorry A12 was
not clearer about that.
: If the coder wants to implement everything via AUTOMETH and not
: tell me, that's okay.
I think you're confusing AUTOMETH with AUTOMETHDEF. AUTOMETH has nothing
to do with implementation. The closest it gets to implementation is to
return references to method objects that might or might not be defined yet.
: But if I was told what methods a class supports, I want to be able
The whole point of separating AUTOMETH from AUTOMETHDEF is so that
we can fake declarations. I don't see the problem. AUTOMETH is
automatically called whenever you ask for the metadata, whether that's
from a dispatcher or not. How specific an answer you get from AUTOMETH
depends on how specific an answer you ask for. That's the intent,
even if the details are a bit vague...
Larry