On OP_SIGNATURE
Since it is not possible to write p5p criticism to the mailing list, I'll have to do it in my blog. @p5p: think over your guidelines. I don't believe that stuff like that needs to be blogged.
DaveM now introduced a new OP_SIGNATURE which assigns run-time args according to the compiled signature.
It basically speeds up these compiled checks
sub f ($a, $b = 0, $c = "foo") {};
=>
sub f {
die sprintf("Too many arguments for subroutine at %s line %d.\n", (caller)[1, 2]) unless @_ <= 3;
die sprintf("Too few arguments for subroutine at %s line %d.\n", (caller)[1, 2]) unless @_ >= 1;
my $a = $_[0];
my $b = @_ >= 2 ? $_[1] : 0;
my $c = @_ >= 3 ? $_[2] : 'foo';
();
}
into one OP, which does the same, similar to the new MULTIDEREF. Moving op chains into C. DaveM is now the goto guy for the big DWIM ops, compressing previous op chains into a single one.
This is far too much for a single op, but previously it was all handled either in ENTERSUB or in user code.
The arity checks should be done in the call op (ENTERSUB), the local assignment should be separate ops, we still have no syntax support for types which could be used previously in user-code (my int $i = $_[0];
) and now we even need type hooks. These can also be added after the SIGNATURE op, but make not much sense there, as side effects will appear to early.
XS calls do not need the checks as they do by their own, but XS calls are easily detected in ENTERSUB.
The assignment to local lexicals is now buried in this single OP, which makes it's now impossible to change the currently only supported call by value to the faster call by reference. I.e. there's still no support to declare call by ref
sub myinc (\$a) { $a++ }; my $i=0; myinc($i); print $i; # => 1
so you still have to use $_[0]
directly, which means @_
still needs to be filled with all args, which makes every signature usage still twice as slow as normal calls without signature declaration. Once for @_
in ENTERSUB and a second time for the named args in SIGNATURE.
So this new OP basically just hides this new slowness by design (blame Zefram for this idea) by bypassing the normal ops which assigned the locals.
Any optimizing compiler now needs to replace this new SIGNATURE op and cannot work on the optree. Fine, it cannot be used as is anyway.
Compiled or run-time polymorphism (dispatch on argument types) now needs to replace SIGNATURE and not ENTERSUB. There's not much difference, both are horrible ops to work with. SIGNATURE is probably easier to replace, but replacing ENTERSUB had its advantages by leaving out all the unneeded recursion, @_ and debugger code. So basically you have now to replace both.
Of course there's still no type support, and still no return type declaration syntax, though it seems the post declaration attribute list can now be used, as :const
is now supported, just for anonsubs only.
So real subs can soon look like:
sub myinc (int \$a) :int { $a++ }
and you can use the faster i_ops
for the result, and since it's a reference, for the lifetime of the caller variable.
Just don't expect that from p5p in the next 5 years. Only all the other dynamic languages, python, ruby, php, javascript announce these features officially, and I have to implement it in private.
p5p still has no idea what they are doing, but probably will also announce it as great breakthrough, as they did with the Zefram signatures before. Which is somewhat funny, announcing the worst of all existing signature implementations as positive. People bought that, so it will work now too.
So far the biggest breakthrough lately was besides the new fast METHOD ops (THANKS!), to go for the :const
attribute for subs (THANKS!), so the other syntax possibilities => type
or perl6 like returns type
or is ro
are now very unlikely to appear. This was a great decision, even if it was done unconsciously, and I can finally go forward.
Reini, please get over it!
If you don't like the decisions p5p makes you have to argue with them on IRC and the mailing list.
If you like a typed language turn towards Perl 6 which will be the future and already can do everything you want.
You bring up good technical points, as always, but, as always, they are couched in insults and ad hominem attacks.
Your technical criticisms have never been the issue. This has:
That paragraph, though it accurately expresses your frustration, adds no value to your argument. Indeed, it diminishes your argument by making you appear as a malcontent with an axe to grind (which is already part of your opening paragraph, also unnecessary).
Having now implemented all my plans with the old slow signatures, I have to take back some of the criticsm above.
OP_SIGNATURE is in fact a really good idea.
I'm still not too keen about the separation of "Too many|few arguments for subroutine" instead of just a "Wrong number of arguments for subroutine $name" which I implemented is now moot, as those strings reside in libperl, and are not compiled as perl data anymore. And there's still another part which checks arity with these error messages. So you have to be consistent.
My other critic of copying @_ twice is also wrong. perl calls - different to xs calls - need to get their args from @_, there's no other way (yet). Having access to the stack from an OP would be nicer (ST 0: first arg, ST 1: second arg) and would make call by ref easier. I haven't implemented that part yet, and probably will not as with OP_SIGNATURE I will have to deal with this differently.
But waiting for op_signature to land makes all this moot, as I have to rewrite everything anyway.
I have tons of more criticism on sigs, but will have wait until the situation stabilizes a bit and I can start fixing it again.
Maybe one: We need the name of the failing call in the error message. caller(0)[3,1,2] gives us these data.
e.g. my perl deparses to
+ ./perl -MO=Deparse -e'sub x(\$a){$a++}'
+ sub x {
+ die sprintf("Wrong number arguments for subroutine %s at %s line %d.\n",
+ (caller(0))[3, 1, 2]) if @_ != 1;
+ $_[0]++;
+ }
This version optimized the arity check to the three possible cases: fixed arity (min_arity==max_arity), slurpy(-1 && min==0) or optional args (-1 && min>0), and only one check mostly, with only one die call, and supports call by ref by rewriting the arg to direct stack access.