On Thu, Mar 05, 2009 at 12:58:21PM -0300, Daniel Ruoso wrote:
: Em Qua, 2009-03-04 às 20:21 +0100, pugs-comm...@feather.perl6.nl
: escreveu:
: > Simplify meaning of Capture and Match in item context to preserve sanity
: >     (an object in item context is always just itself, never a subpart)
:   sub foo { return 1 }
:   my $a = foo();
: That is currently expressed as taking the capture (in this case \(1))
: and coerce it to the appropriate context, in order for that to work,
: Capture need to do some DWIMmery when used in item context.
: What I have in mind is:
:   A capture in item context returns the first positional argument if 
:   there is only one (named or positional), otherwise it returns itself 
:   (so it can be used as both an array and a hash).

That's fine, and consistent with the interpolation of captures into list
context when you say my @a = foo().

: > The invocant (if any) of a Capture is now always considered 1st positional.
: Unless you're a method, then it's really an invocant...
: That seems to mean that you actually have two different APIs to talk to
: a capture, which are:
:   * I don't care about invocant, gimme the positional args
:   * I do care about invocant, gimme the positional args

Refactor that the other way.

    * Give me the arguments
    * Did the first argument have a colon after it instead of comma?

: So, if you don't care about invocant, it is just a regular positional
: argument, but if you do care, it is not a positional argument. It looks
: like the old "my $self = shift"...

You use the P5 formulation there to make it sound bad, but it isn't.
The invocant is always passed as an argument anyway.  It has to be availble
as self, whether or not it gets bound to a user-defined variable.

: What really got me confused is that I don't see what problem this change
: solves, since it doesn't seem that a signature that expects an invocant
: (i.e.: cares about invocant) will accept a call without an invocant, so
: "method foo($b,$c) is export" still need to have a transformed signature
: in the sub version of foo.

This is simplifying the invocation semantics.  We don't invoke subs
and methods differently.  Binding doesn't give a rip about invocants.

The : in a signature merely tells the compiler that it doesn't need to
supply its own implicit $: on the front of the actual signature.  When
you ask a method for its signature, it always reports something with
an invocant on the front, ($: $a,$b,$c) if it's implicit.  Binding
sees that merely as ($, $a,$b,$c).  There's no extra shifting going on;
there's no array being mutated.

In implementation, there is no difference between a sub and a method.
The signature of a method will always have its first argument marked
as invocant, but binding doesn't care, so when we export as a sub,
the signature stays with the colon on the front, and the multi
dispatcher just ignores that.  If it decides to call the aliased
method, it just calls it as an ordinary subroutine, and the binding
in the method again just ignores whether there were colons in
either the capture or the signature.  The first argument is
simply bound to whatever the signature asks for.

An interesting corollary is that self is potentially legal in
an ordinary sub; it just means the first argument that was passed,
regardless of how it was bound.

Another corollary is that, in addition to exporting methods as subs,
you can go the other way and "import" methods from subs.  If you
install a sub as body of a method, it just gets invoked the same way,
and the invocant is bound as the first argument to the function.

So what's the difference between a function and a method then?
Nothing on the implementation end.  The only difference is in the
call end; we have different calling notations that invoke different
dispatchers.  Each of those dispatchers resolves the membership
and ordering of its multiple candidates in its own way, using some
combination of namespace and type filtering, but not the presence or
absence of a ':' in either the Capture or the Signature.

Once the candidate list is resolved down to individual Code entries,
however, the dispatchers are identical in how they dispatch to the
individual functions/methods.  If necessary we can install a call
primitive that requires a singular code object and invokes it as a
function, rather than relying on foo() to do both multiple dispatch
and low-level invocation.  Or maybe we just define .() to mean that,
and make ()/.() inconsistent with other dotless/dotty postfixes.


Reply via email to