Re: new Capture behavior (Was: Re: r25685 - docs/Perl6/Spec)
Em Qui, 2009-03-05 às 18:43 -0800, Jon Lang escreveu: OK; let me get a quick clarification here. How does: say Hello, World!; This is the equivalent to say.postcircumfix:( )( \(Hello, World) ); differ from: Hello, World!.say; This is just Hello, World!.say; Meaning, the first dispatch is private to the sub, the second to the object. or: say $*OUT: Hello, World!; $*OUT.say(Hello, World!); dispatch is private to $*OUT... And more generally, would there be a reasonable way to write a single routine (i.e., implementation) that could be invoked by a programmer's choice of these calling conventions, without redirects (i.e., code blocks devoted to the sole task of calling another code block)? This is exactly what this change has enabled. Now it doesn't matter if your signature had an invocant or not, if that code is available as a method it can be dispatched as a method, if it is available as a sub, it can be dispatched as a sub, which means that you can install a sub as a method and a method as a sub, it doesn't mattter... Could you use binding? my sub say (String *$first, String *...@rest, OStream :$out = $*OUT, OStream :$err = $*ERR) { ... } role String { has say:(String $first: String *...@rest, OStream :$out = $*OUT, OStream :$err = $*ERR) := OUTER::say; } semantically, yes... but I don't think there's a syntax to bind a sub as a method... You need to do it through the meta api at this moment... maybe we could have something in the lines of method bar ::= bar; or even method bar is external bar; daniel
Re: new Capture behavior (Was: Re: r25685 - docs/Perl6/Spec)
HaloO, Daniel Ruoso wrote: Em Qui, 2009-03-05 às 18:43 -0800, Jon Lang escreveu: And more generally, would there be a reasonable way to write a single routine (i.e., implementation) that could be invoked by a programmer's choice of these calling conventions, without redirects (i.e., code blocks devoted to the sole task of calling another code block)? This is exactly what this change has enabled. Now it doesn't matter if your signature had an invocant or not, if that code is available as a method it can be dispatched as a method, if it is available as a sub, it can be dispatched as a sub, which means that you can install a sub as a method and a method as a sub, it doesn't mattter... [..] semantically, yes... but I don't think there's a syntax to bind a sub as a method... You need to do it through the meta api at this moment... With this nice unification of sub and method as far as the binder is concerned I wonder how one implements methods for classes one is supertyping from without an is also clause. With the venerable example of Complex supertyping Num we should have method im (Num $x:) { return 0 } method re (Num $x:) { return $x } outside of any class and nonetheless allow the method invocation syntax 3.im without the object slot dispatcher complaining. That is I want to avoid class Num is also { method im { return 0 } method re { return self } } at least as syntactical form. I think in the end the class Num gets the additional methods one way or another. But it seems open classes have acquired a design smell of late. Or why is the process called monkey patching? Regards, TSa. -- The unavoidable price of reliability is simplicity -- C.A.R. Hoare Simplicity does not precede complexity, but follows it. -- A.J. Perlis 1 + 2 + 3 + 4 + ... = -1/12 -- Srinivasa Ramanujan
Re: new Capture behavior (Was: Re: r25685 - docs/Perl6/Spec)
Em Qui, 2009-03-05 às 12:58 -0300, Daniel Ruoso escreveu: 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. Thinking again, Unless that actually means that we're really removing all the runtime semantics around the invocant... and methods implicitly do my $self = shift all the time... That'd be sad... we loose invocant semantics... SMOP will require a HUGE refactoring... :( daniel
Re: new Capture behavior (Was: Re: r25685 - docs/Perl6/Spec)
Daniel Ruoso wrote: Daniel Ruoso escreveu: 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. Thinking again, Unless that actually means that we're really removing all the runtime semantics around the invocant... and methods implicitly do my $self = shift all the time... That'd be sad... we loose invocant semantics... SMOP will require a HUGE refactoring... :( Remember that Captures are also being used as Perl 6's answer to references. When used in that way, problems arise when you treat a single item as being fundamentally different from a one-item list. -- Jonathan Dataweaver Lang
Re: new Capture behavior (Was: Re: r25685 - docs/Perl6/Spec)
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. Larry
Re: new Capture behavior (Was: Re: r25685 - docs/Perl6/Spec)
Larry Wall wrote: snip 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. snip This all sounds reasonable to me, but I'm wondering how to make it work in certain ways that I would like. Case in point, with my Set::Relation module. That module is an object-oriented derivation of a module design that was originally just functional, having a collection data type as its main operand and all of its routines originally just being functions. The object-oriented Set::Relation is somewhat unnatural because its functionality is not supposed to consider any particular routine argument as special, that is an invocant. The reason I made it OO was so users wouldn't have to use Package.func syntax and wouldn't have to import the routines. Now, perhaps one solution is to make this non-OO and export its routines, but I figure people may want to say $arg1.foo($arg2) or whatever. Here's a question: Say I had an N-adic routine where in OO terms the invocant is one of the N terms, and which of those is the invocant doesn't matter, and what we really want to have is the invocant automatically being a member of the input list. For example, say we had method natural_join of R (R $topic: Array of R $others) but what we really want is method natural_join of R (Array of R $topic) so that within the natural_join method we can simply refer to the array $topic and the invocant just happens to be one of its elements, as if natural_join were just a function with no invocant. So, is there some way, or is it reasonable for there to be, to declare a method in Perl 6 such that say it is declared with say an Array of R or Set of R etc parameter and that parameter is marked somehow, maybe with a trait, to say it automatically gains the invocant as one of its elements? This is sort of the opposite of unpacking array parameters. Maybe something like method natural_join of R (Array of R $topic is enveloping self), but keep in mind that it should work if the parameters in question are named instead. Then one could invoke it with say $r1.natural_join( [$r2, $r3] ) or some such. I'm thinking maybe there was an answer to this in Synopsis 6 but I didn't see it. Thank you. -- Darren Duncan
Re: new Capture behavior (Was: Re: r25685 - docs/Perl6/Spec)
Darren Duncan wrote: Here's a question: Say I had an N-adic routine where in OO terms the invocant is one of the N terms, and which of those is the invocant doesn't matter, and what we really want to have is the invocant automatically being a member of the input list. How about allowing submethods to be declared outside of classes and roles as well as inside them? When declared inside a class or role, it is declared in has scope, and works as described; when declared elsewhere, it is declared in my scope, and works just like a sub, except that you're forced to specify an invocant in the signature(s). You could then use the same sort of tricks that subs can use to specify alternate signatures, including the one that lets the positional arguments be filled out in any order. -- Jonathan Dataweaver Lang
Re: new Capture behavior (Was: Re: r25685 - docs/Perl6/Spec)
Darren Duncan wrote: So, is there some way, or is it reasonable for there to be, to declare a method in Perl 6 such that say it is declared with say an Array of R or Set of R etc parameter and that parameter is marked somehow, maybe with a trait, to say it automatically gains the invocant as one of its elements? This is sort of the opposite of unpacking array parameters. Maybe something like method natural_join of R (Array of R $topic is enveloping self), but keep in mind that it should work if the parameters in question are named instead. Then one could invoke it with say $r1.natural_join( [$r2, $r3] ) or some such. I should further qualify my question/request, which should also bring it more on topic with the thread, is that ideally the same single routine declaration would DWIM regardless of whether it is invoked as $obj.meth syntax or whether the routine is exported and called with meth($obj) syntax. Larry said essentially that the invocant is just another parameter for the most part. And what I'm asking is a way that the invocant could be combined into a distinct Array|Set|etc parameter when an invocant exists, and the parameter is just itself otherwise. -- Darren Duncan
Re: new Capture behavior (Was: Re: r25685 - docs/Perl6/Spec)
OK; let me get a quick clarification here. How does: say Hello, World!; differ from: Hello, World!.say; or: say $*OUT: Hello, World!; in terms of dispatching? And more generally, would there be a reasonable way to write a single routine (i.e., implementation) that could be invoked by a programmer's choice of these calling conventions, without redirects (i.e., code blocks devoted to the sole task of calling another code block)? Could you use binding? my sub say (String *$first, String *...@rest, OStream :$out = $*OUT, OStream :$err = $*ERR) { ... } role String { has say:(String $first: String *...@rest, OStream :$out = $*OUT, OStream :$err = $*ERR) := OUTER::say; } That (or something like it) might be doable. But in the spirit of TIMTOWTDI, I'd like to explore another possibility: what difficulties would arise from allowing subs to have signatures with invocants, which in turn allow the sub to be called using method-call syntax (though possibly not method dispatch semantics)? In effect, allow some syntactic sugar that allows properly-sigged subs outside of a role to masquerade as methods of that role. -- Jonathan Dataweaver Lang