FAQ
Not setting @_ could be a problem for tail-end recursion using goto &foo;

I love the signatures. I also love controlled and sane use of goto &sub. I
would not be happy if signatures made goto &sub harder.

When you say @_ is unset, do you mean it is empty, but still a unique array
for each function? if @_ was arguments to a function higher up the stack I
could see that as a total disaster (but I am hoping nobody proposed that).

If by empty you mean @_ will be an empty array for functions with
signatures, that would not bother me so much.

-Chad
On Wed, Mar 23, 2016 at 7:34 AM, Dave Mitchell wrote:
On Mon, Feb 29, 2016 at 06:47:42PM +0000, Dave Mitchell wrote:
On Thu, Dec 03, 2015 at 03:21:25PM +0000, Dave Mitchell wrote:
What should the semantics of @_ be for a sub that has a signature?
Here's another stab at the semantics of @_ suppression and signatures.

I've divided it into two sections. First what I think think all the
issues and proposed solutions are (notionally without my personal
preferences/prejudices showing too much), and second, what I personally
think we should do.
Any opinions?

Also, specifically for 5.24, I'd like to change the signature docs to the
effect that in future @_ might not (by default) get set on signature subs.
Section I: the issues
=====================

A: what should @_ be/contain at runtime if suppressed? Note that this
issue can't be avoided, due to all the weird ways it can be accessed, such
as 'local *args = $::{_::};'. Options:

1 same as &f; i.e. remains that of the caller.

pros: it's the fastest option
cons: action at a distance; especially several nested @_-suppressed
subs, where the inner one will see the @_ of several
callers above.

2 On entry, each sub does the moral equivalent of
local *_ = $some_tied_array_that_croaks_on_access;
This special array might be either global, or unique to each sub
(like @_ is currently unique to each sub).

pros: at runtime, will quickly flush out unintended uses of @_.
cons: relatively slow to set up and take down;
has issues with '&foo' and '&goto foo' (see C below).

3 On entry, each sub does the moral equivalent of
local *_{ARRAY}'
which would initially leave the AV slot of PL_defgv as NULL.
Any usage of @_ within the sub would auto-vivify a new @_, which
would be discarded on sub exit. (Aristotle suggested this.)

pros: in terms of speed it's somewhere between A1 and A2;
it has an obvious behaviour with '&foo' and '&goto foo':
i.e. they're called with no args, or with whatever @_ has
been set to (also see C below).
cons: stray uses of @_ at runtime won't be detected (but see B below)
B: what should accesses of @_ in the sub do at compile time?

Aristotle suggested that in the presence of @_-suppression,
'use strict "vars"' should trap @_ usage; or to put it another way,
in that scope, @_ becomes a non-special-cased var for 'strict var'
purposes, and so needs to be referred to as @::_ or $::_[0] or 'our
@_' to avoid compile-time errors.

Although Aristotle didn't say it explicitly, I'm assuming that
this extends to things like 'shift' etc; so 'shift' within a sub is
assumed to be short for 'shift @_' and so gives a compile-time error
unless written explicitly as 'shift @::_'.

This of course doesn't cover all possible accesses of @_, but is
likely to pick up most of the common ones.

'&foo;' and 'goto &foo;', if regarded as being short for
'&foo(@_) and a hypothetical 'goto &foo(@_)', might also be
subject to this stricture: see (C) below.

pros: detects some common coding errors, especially where existing
code is being converted to signatures plus @_-supppressed.
cons: I dunno really - perhaps some people won't like writing
'@::_ = (1,2,3)'?

C: what should C<&foo;> and C<goto &foo> do under @_-suppression?

The two obvious sets of semantics are:

1 &foo is equivalent to &foo(@_), i.e. they use the current
value of @_, and whatever of A and B above are selected will
affect the compile-time and run-time behaviour of trying to use the
current value of @_.

2 Where @_ hasn't been modified, there is an implied assumption that
&foo and goto &foo reuse the args that were passed to the existing
sub; in that interpretation, with these:
sub bar($a,$b) { &foo; }
sub bar($a,$b) { goto &foo }
bar would be expected to pass ($a,$b) rather than () to foo.

The main con of (C2) is that it quickly becomes inconsistent:
sub bar($a,$b) { &foo; } # foo($a,$b)
sub bar($a,$b) { shift; &foo; } # foo($a,$b) or foo($b)?
sub bar($a,$b) { @=(1); &foo; } # foo($a,$b) or foo(1)?

The main pro of (C1) is that that is has a consistent behaviour;
it's main con is that people might think that (C2) is logical
behaviour. This might be less of an issue if the latter part of (B) is
implemented; that is, &foo; would be regarded as being equal to
'&foo(@_)'; and so dies under 'strict vars' unless explicitly written
as '&foo(@::_)' This would force coders to explicitly write what they
mean to happen.

'goto &foo;' is is more problematic as there's no way (as far as I'm
aware) to write 'goto &foo(@::_)'. So in this case people would
have to explicitly write
no strict 'vars'; goto &foo;
or
our @_; goto &foo;

3 Then there's the issue of whether the conceptual
local *_ = $some_tied_array_that_croaks_on_access;
or
local *_{ARRAY}
at the start of the sub should be unlocalised prior to doing goto
&foo.

D: should signatures and @_=suppression be orthogonal.

1 Various people have suggested that @_-suppression should be
orthogonal to signatures.

pros: the main advantage of this (if I'm summarising people
correctly) is that it allows, when converting existing code to
signatures, to say "this file has signatures but still has
@_", so that missed 'shift', '&foo' etc still work.
cons: extra complexity; (B) would already allow most such uses to be
detected at compile time

2 Assuming orthogonality, there's also the issue of whether
'use feature "signatures"' on its own should do @_-suppression;
i.e. the current default should change.

pros: when enabling signatures, people get the performance benefit
of @_-suppression by default;

cons: we're changing the existing behaviour of signatures (but
con con, they are experimental).

3 What should @_ suppression mean outside the scope of a sub?

Assuming it's done by a pragma, then what should this do?:

no snails; # or whatever the pragma is

sub f {
shift; # will do whatever we agree for A and B above
}

shift; # what happens here?

4 Assuming its orthogonal, what syntax should be used to enable
suppression?:

* a new pragma (to be be bikeshedded), e.g.:

no snails;

* a modification of the existing feature pragma; e.g.:

use feature 'signature'; # sigs and @_ suppressed
use feature 'arg_signature'; # sigs and @_
no feature 'arg_signature'; # no sigs; @_
no feature 'signature'; # no sigs; @_

NB: this wouldn't allow the 'no sigs, no @_ combo'

* a per-sub pragma, e.g.

sub foo :arg_array(1) {} # default - @_ is populated
sub foo :arg_array(0) {} # @_ isn't populated
sub foo($a,$b) :arg_array(0) {} # default: @_ isn't populated
sub foo($a,$b) :arg_array(1) {} # @_ is populated

* something in the signature syntax itself to indicate @_
should be provided for this sub.

This also wouldn't allow the 'no sigs, no @_ combo'

E: Under @_-suppression, would there be ways of accessing (parts of) the
sub's arg list?

1. We could not bother; if people really need it they can avoid
signatures.

2. It could be provided as a new field returned by caller()
(Note that caller already does something similar if called from the
package DB: it populates @DB::args with a (non-ref-counted) copy
of the caller's args, which is as buggy as a very buggy thing).

3. New ops could be provided which access arg elements or slices etc,
then XS modules could provide access.


F: For 5.24, should we warn in perlsub.pod and perldelta that @_ may
change?

Any changes aren't going to happen for 5.24, but if we reach rough
consensus here on what *will* change (especially if by default
signatured subs will no longer get @_), then should we update the docs
to warn people not to rely on @_ etc (or whatever it is we agree)?


Section II: What I propose.
==========================

My own personal preferences are:

A3 and B - i.e. roughly what Aristotle proposed. This doesn't have too bad
performance impact, and has consistent behaviour with just a couple of
simple rules to remember, which are:

In the scope of 'no snails' (or whatever),

1. Each sub has the logical equivalent of
local *_{ARRAY}'
at its start; so @_ starts off non-existent, and will be
autovivified if used, and freed at the end of the sub.

2. @_ is no longer special-cased as regards 'use strict "vars", and
so gives a compile-time error like any normal array unless
used as '@::_', $::_[0]', or 'our @_' etc.
Implicit uses of @_, such as in 'shift', '&foo' and 'goto &foo' are
treated as using @_ too, so they will need to be rewritten as
'shift @::_', '&foo(@::_)', 'our @_ = (,...); goto &foo' etc.

These would be coupled with C1, which then provides predicable behaviour
for things like '&foo;'.

For C3, the local '*_{ARRAY}' shouldn't be unlocalised when doing goto
&foo;

D: as for orthogonality, I still think its overkill, especially with
B providing compile-detection of most existing usages of @_ when
converting
exiting files, but if people strongly want it, I won't stand in their way.
For D2, I am *strongly* of the opinion that 'use feature "signatures"'
by itself should do @_-suppression by default, without the need for a
further pragma.

I don't have a strong feeling for what the pragma/attribute or whatever
should look like.

If @_-suppression is in scope outside a sub, then I think if (B) is
selected, then 'use strict "vars"' should still apply. Other than that, the
pragma should have no effect.

E: ways of accessing caller args when @_ is suppressed.

I'm of the opinion that this is not needed; if people really want it,
via caller() or new ops or whatever, then I'd prefer this to be something
that could be done (preferably by someone else) at a later date; unless
people feel that the mechanism must be made available at the same time
that @_-suppression is added to core.

F: for 5.24, I think we should warn in perlsub and perldelta.


--
Dave's first rule of Opera:
If something needs saying, say it: don't warble it.
--
Hofstadter's Law: It always takes longer than you expect, even when you
take into account Hofstadter's Law.

Search Discussions

Discussion Posts

Previous

Follow ups

Related Discussions

Discussion Navigation
viewthread | post
posts ‹ prev | 32 of 34 | next ›
Discussion Overview
groupperl5-porters @
categoriesperl
postedDec 3, '15 at 3:21p
activeMar 25, '16 at 2:25p
posts34
users13
websiteperl.org

People

Translate

site design / logo © 2021 Grokbase