sub bar ($a,$b,$c,:$mice) { say $mice }
sub foo (\$args) { say $args.perl; &bar.call($args); }
The C<.call> method of C<Code> objects accepts a single C<Capture>
object, and calls it without introducing a C<CALLER> frame.
And from S12:
In addition to C<next METHOD>, the special function C<call> dispatches
to the next candidate, possibly with a new argument list:
call; # calls with the original arguments
call(); # calls with no arguments
call(1,2,3); # calls with a different set of arguments
And back in S06:
The entire argument list may be captured by the C<\$args> parameter.
It can then be passed to C<call> as C<[,] =$args>:
# Double the return value for &thermo
&thermo.wrap( -> \$args { call([,] =$args) * 2 } );
The inconsistency between these three things called "call" is vexing to
me. One is a method and takes a capture and only a capture. The second is
a special function and takes an argument list, but also has a special
arglistless form that passes on the original arguments. The third is a
function that takes only a function list, but apparently lacks a
arglistless form (otherwise, why bother with capturing an arglist in the
example?).
I believe the current spec works. I just think the inconsistency is
bad--the three things called "call" do very similar things, but take
completely different arguments. I suspect this is just historical smear
and we just need to back up and normalize.
(Let me quickly note here that I don't think it's possible to write a
subroutine or method that can take either a bare argument list or a
Capture and treat them the same, because of the intractable ambiguity that
would arise in the case of an argument list that actually contains a
single capture as its only positional element. If I'm mistaken, then
other avenues open up. But I don't think I am.)
Audrey confirmed to me on IRC that the motivation for the arglistless form
was that passing on the original arguments will likely be one of the most
common uses of call. And I certainly can't argue with that, I agree.
But why, then, does .call not have an argumentless form? (Because we
can't write user-defined methods, short of C<is parsed> tricks, that
differentiate between .meth and .meth()? We can't write user-defined subs
that do that either, AFAIK...)
Might I propose the following normalization:
1. .call, method definition call(), and .wrap call all take captures.
2. .call() and both types of call() all pass on the arguments of the
current subroutine.
3. To call with no arguments, use .call(\()) and call(\()).
4. Introduce some syntax for getting a capture of the current argument
list explicitly. Perhaps $?ARGS or $?_ or $?CAPTURE. One shouldn't
have to choose between repeating your 20 parameters in order to take a
capture of them, and eliminating your nice self-documenting 20
parameter names so you can use the easy \$arglist trick.
Trey
> 2. .call() and both types of call() all pass on the arguments of the
> current subroutine.
> 3. To call with no arguments, use .call(\()) and call(\()).
I have no problem with that, but the original form should probably exist
too. I don't know if that's called invoke or what, but something that
takes an arglist and constructs the capture to pass on would be very
helpful to most users.
> 4. Introduce some syntax for getting a capture of the current argument
> list explicitly. Perhaps $?ARGS or $?_ or $?CAPTURE. One shouldn't
> have to choose between repeating your 20 parameters in order to take a
> capture of them, and eliminating your nice self-documenting 20
> parameter names so you can use the easy \$arglist trick.
I like the idea in 4, even though I'm not sure that I follow the rest of
your logic. Having access to a variable that contains the current
argument list called $?ARGS seems to be in line with the rest of the $?
state variables that are provided.
So, in general, I think the only thing missing is something like invoke
so that:
invoke(1,2,3);
is identical to:
call(\(1,2,3));
and:
invoke([,] =$?ARGS);
is identical to:
call($?ARGS);
is identical to:
call();
Certainly a distinction on call vs call() is not what Perl 6 programmers
will come to expect from the rest of the language, and I see no pressing
reason to introduce it here.
It would be suboptimal to give something so related a name that is
completely unrelated. If we had such a thing it should "callv" or
"callargs" or some such. But it's not yet clear to me that this is
frequent enough to deserve the sugar over call(\(...)).
By the way, call() is just short for nextroutine().call() or some such,
where nextroutine() is a mystical call that retrieves the next candidate
based on what kind of dispatcher we're in.
: >4. Introduce some syntax for getting a capture of the current argument
: > list explicitly. Perhaps $?ARGS or $?_ or $?CAPTURE. One shouldn't
: > have to choose between repeating your 20 parameters in order to take a
: > capture of them, and eliminating your nice self-documenting 20
: > parameter names so you can use the easy \$arglist trick.
:
: I like the idea in 4, even though I'm not sure that I follow the rest of
: your logic. Having access to a variable that contains the current
: argument list called $?ARGS seems to be in line with the rest of the $?
: state variables that are provided.
Uh, no, $? variables are supposed to be compile-time constants. That's why
there's no $?SELF anymore.
Since individual constraints within the siglet are considered to be
"anded", it might be possible to declare both a capture and the rest of
the parameters like this::
sub foo (\$args $a, $b, $c)
In other words we relax the constraint that \$x has to come at the
end, so \$x would just take a snapshot of the rest of the args and
keep processing the binding to any remaining parameters.
: So, in general, I think the only thing missing is something like invoke
: so that:
:
: invoke(1,2,3);
:
: is identical to:
:
: call(\(1,2,3));
:
: and:
:
: invoke([,] =$?ARGS);
:
: is identical to:
:
: call($?ARGS);
:
: is identical to:
:
: call();
We might prefer a three-way distinction just to avoid user confusion:
call; no args allowed, always uses existing parameters
callcap($capture) one arg, must be capture (plus named?)
callargs($a: $b, $c) same as callcap(\($a: $b, $c));
(plus the corresponding dot forms). Alternately, just keep callargs and
force callcap to be written callargs([,] =$capture). After all, if you're
going to do anything with the args, you're usually not interested in the
whole original capture by itself.
What we really need is a unary operator that is sugar for [,](=(...)). Just
don't anyone suggest *. :-)
Candidates:
callargs(`$foo)
callargs(_$foo)
callargs(|$foo)
callargs(「$foo)
Another approach would be to give captures a sigil that autoinserts, and
you'd have to \ it to suppress that, much like @foo always interpolates
into list context. Then we just get something like
callargs(「x)
and the mixed declaration above would be
sub foo (「args $a, $b, $c)
: Certainly a distinction on call vs call() is not what Perl 6 programmers
: will come to expect from the rest of the language, and I see no pressing
: reason to introduce it here.
Yes, that would be a mistake. Macros that abuse () are a design smell.
Larry
invoke is just a very commonly used name in places like parrot and XS,
so I thought of it right off the bat.
I think your call, callargs and callcap are fine looking things.
As for $?ARGS, you're right, I was forgetting that it's not compile-time
constant.
Would $?ROUTINE have access to its current invocation? In other words,
could $?ROUTINE.args or $?ROUTINE.invocation.args find the current
invocation and ask for its capture? Why do I ask for that when you've
already said that signatures could include a capture? Macros. A macro
might want to do something with its caller's arguments, but doesn't know
what localized name it will have been given. If it can ask for its
$?ROUTINE, then it's always going to work.
macro debug() {
if $*ENV<DEBUG> {
q:code{
say("DEBUG: ", $?ROUTINE.name,
" called with: ",
Dumper($?ROUTINE.args))
};
} else {
q:code{1};
}
}
> What we really need is a unary operator that is sugar for [,](=(...)). Just
> don't anyone suggest *. :-)
I was thinking about that. I wonder if [\] would make sense, or is that
just begging to have in-editor parsers fall over screaming ;)
Other options might be (in decreasing order of my fondness for them):
callargs(<-- $foo) -- a nice inverse to ->
callargs($\ $foo) -- mnemonic: Dereference this capture
callargs(.* $foo) -- Ok, only to be passive-aggressive ;)
callargs(*\ $foo) -- kind of the same idea as $\
>
> Candidates:
>
> callargs(`$foo)
> callargs(_$foo)
> callargs(|$foo)
> callargs(¢$foo)
None of these LOOK like capture-expansion to me other than _ which I'm
always hesitant to mess with. | seems too confusing.
> Another approach would be to give captures a sigil that autoinserts, and
> you'd have to \ it to suppress that, much like @foo always interpolates
> into list context. Then we just get something like
>
> callargs(¢x)
>
> and the mixed declaration above would be
>
> sub foo (¢args $a, $b, $c)
I've been a Perl programmer for 15 years, so I don't know why adding a
sigil would bother me, but it does... Can't give you a good reason,
though, so perhaps it's moot. Unicode sigils might have a valid ickiness
factor, though. I can't figure out what the ascii form of ¢ would be...
Certainly most expansions involving c and/or | are going to have
ambiguity problems.
That would be quite close to [\+] [\,] etc.. from S03:
S03> say [\+] 1..* # (1, 3, 6, 10, 15, ...)
--
Markus Laire