develooper Front page | perl.perl5.porters | Postings from November 2019

Parameter Attributes

Thread Previous | Thread Next
From:
Dave Mitchell
Date:
November 28, 2019 17:01
Subject:
Parameter Attributes
Message ID:
20191128170100.GA3573@iabyn.com
=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.

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About