Front page | perl.perl5.porters |
Postings from May 2023
Re: Limitations of Attributes
Thread Previous
|
Thread Next
From:
Dave Mitchell
Date:
May 5, 2023 10:59
Subject:
Re: Limitations of Attributes
Message ID:
ZFThcJEt3BQHcVBO@iabyn.com
On Tue, May 02, 2023 at 02:33:04PM -0500, Ovid wrote:
> For example, attributes in signatures are a syntax error:
>
> sub foo ($bar :some_attr) { ... }
As a data point, this is a copy of my signature attributes proposal from
2019. It doesn't address stuff like being dynamic, but it contains a
useful description of how attributes are currently implemented.
--------------------------------------------------------------
=head1 Parameter Attributes
=head2 Synopsis:
sub f ($x :foo, $y :bar(baz) bar2(baz2), ...) { ... }
analogous to:
my $x :foo;
my $y :bar(baz) bar2(baz2);
We should support parameter attributes. I think this is a relatively
uncontroversial proposal.
What exactly should the semantics be? Lets first review the current syntax
as applied to 'my' declarations:
my ($x, $y) :foo(foo_arg) :bar(bar_arg);
is roughly equivalent to
use attributes ();
my ($x,$y);
attributes->import(, __PACKAGE__, \$x, "foo(foo_arg)", "bar(bar_arg)");
attributes->import(, __PACKAGE__, \$y, "foo(foo_arg)", "bar(bar_arg)");
except that some attributes are built-in and are recognised and handled
directly by the lexer / parser, without attributes.pm ever getting
involved.
Note that attributes.pm says that attributes on variables are currently
experimental, although in practice we've supported things like
my $x : shared; for years.
As an aside, note that any argument to the attribute is scanned as a
single-quoted string - i.e. like q(...) - but is otherwise uninterpreted
by Perl itself. Thus hypothetically a constraint expressed as an
attribute, e.g.
sub foo ($x :where($x ne '(' ));
wouldn't get correctly parsed unless we handled it specially somehow,
which seems to be an argument for *not* using attributes for such things,
and instead use purpose-designed syntax, like, for example:
sub foo ($x where $x ne '(', ...)
Second and subsequent attributes may be preceded by a colon, but don't
have to be: these are equivalent:
my $x :foo :bar(1) :bar(2);
my $x :foo bar(1) :bar(2);
Thus for signatures, the obvious semantics would be that
sub f ($a :foo, ...) {...}
is equivalent to
sub f { my $a :foo; $a = $_[0]; .... }
The exact details of when attributes->import() is called is discussed in
the "Scope and Ordering" thread.
Once available, built-in attributes could in principle be used where Perl
6 uses traits, e.g.
sub f($x is ro) { ... } # Perl 6
sub f($x :ro) { ... } # Perl 5 ???
See the "Aliasing and Read-only variables" thread for more detailed
proposals.
Attributes can't be used on a placeholder parameter:
($x :foo) # ok
($ :foo) # error
Attributes can't be used with aliasing, except for slurpies (which alias
individual elements rather than the aggregate itself):
(\$x :foo) # error
(\@a :foo) # error
(\%h :foo) # error
(*$x :foo) # error
(*@a :foo) # ok - like: my @a: foo; \$a[0] = ...; \$a[1] = ...
(*%h :foo) # ok - like: my %h: foo; \$h{..} = ...; \$h{..} = ...
Note that in Perl 6 and some CPAN signature modules, the 'method' keyword
declares an implicit $self parameter, whose name can be overridden using
a postfix ':':
method foo($x, $y) { $self->{$x} = $y } # implicit $self
method foo($me: $x, $y) { $me->{$x} = $y } # explicit invocant
I have no plans to introduce such a 'method' keyword, but if we did,
we might need different syntax for the invocant, as the ':' would be
interpreted as the start of an attribute unless the toker was clever and
we are very careful that all signature syntax is capable of being
disambiguated.
--------------------------------------------------------------
=head1 Scope and Ordering
...
=head2 Ordering of evaluation of terms
There is much external visibility, both from explicit execution of things
like default expressions and constraints, and implicitly from things like
FETCH(), overloaded stringify, and attribute handlers. The question is how
are these ordered, and what do we guarantee?
I propose that a few aspects of ordering are well defined; everything
else is left undefined, to allow us to change things in different releases
for the purposes of optimisation etc.
Within a single parameter element, we guarantee this order:
1) attributes->import() is called as appropriate for any :attribute;
2) the default expression (if present and needed) is run;
3) the parameter variable is bound to its argument or default value;
4) the constraint expression (if any) is run.
Between parameter elements, we guarantee that parameters are processed in
left-to-right order.
--------------------------------------------------------------
--
Indomitable in retreat, invincible in advance, insufferable in victory
-- Churchill on Montgomery
Thread Previous
|
Thread Next