Mailing List Archive

Limitations of Attributes
Hi all,

Attributes could really use a rethink in a number of ways and I'm curious
if anyone has put any thought into this?

For example, attributes in signatures are a syntax error:

sub foo ($bar :some_attr) { ... }

It would also be nice if the attribute arguments could be dynamic instead
of just strings. Here's an example, using the signatures from Type::Tiny. I
have some client code which looks like this:

use Custom::Sigs 'search_signature';

signature_for function => search_signature();

sub function {...}

That particular signature is shared in several places, so it's maintained
in only one place. At a minimum, I'd love to do this:

use Custom::Sigs 'SEARCH';

sub function :signature(SEARCH) {...}

And replace SEARCH with the results of the sub call without nasty eval
hacks. I'm actually working on some code to try to handle the latter case,
but so far I've been using the Marpa parser to develop a BNF grammar to
parse the Perl code in the attribute and install the signature. It's very
painful.

Best,
Ovid
Re: Limitations of Attributes [ In reply to ]
>
>
> use Custom::Sigs 'SEARCH';
>
> sub function :signature(SEARCH) {...}
>
> And replace SEARCH with the results of the sub call without nasty eval
> hacks. I'm actually working on some code to try to handle the latter case,
> but so far I've been using the Marpa parser to develop a BNF grammar to
> parse the Perl code in the attribute and install the signature. It's very
> painful.
>
>
just repeating my previous idea - what about `extends` for functions? eg:

package Foo {
sub SEARCH (... signature ...);
}

sub function :extends(&Foo::SEARCH) { ... }

later extended signature support for setting fixed value (in opposite to
default value) of parameter, eg:

sub function :extends(&Foo::SEARCH) ($search_key := value = q (fixed
value)) { ... }

Best regards,
Brano
Re: Limitations of Attributes [ In reply to ]
On 2023-05-02 21:33, Ovid wrote:
> Attributes could really use a rethink in a number of ways and I'm
> curious if anyone has put any thought into this?
>
> For example, attributes in signatures are a syntax error:
>
> sub foo ($bar :some_attr) { ... }
>
> It would also be nice if the attribute arguments could be dynamic
> instead of just strings. Here's an example, using the signatures from
> Type::Tiny. I have some client code which looks like this:
>
> use Custom::Sigs 'search_signature';
>
> signature_for function => search_signature();
>
> sub function {...}
>
> That particular signature is shared in several places, so it's
> maintained in only one place. At a minimum, I'd love to do this:
>
> use Custom::Sigs 'SEARCH';
>
> sub function :signature(SEARCH) {...}
>
> And replace SEARCH with the results of the sub call without nasty eval
> hacks. I'm actually working on some code to try to handle the latter
> case, but so far I've been using the Marpa parser to develop a BNF
> grammar to parse the Perl code in the attribute and install the
> signature. It's very painful.
>

The set of instances of <function> could be implemented as
a set of minimal instances called <_function>,
and a single "wrapper" implementation of <function> itself inside some role,
that handles all the interfacing,
and then hands over to the appropriate instance of <_function>?

-- Ruud
Re: Limitations of Attributes [ In reply to ]
On Wed, May 3, 2023 at 10:15?AM Ruud H.G. van Tol via perl5-porters <
perl5-porters@perl.org> wrote:

> The set of instances of <function> could be implemented as
> a set of minimal instances called <_function>,
> and a single "wrapper" implementation of <function> itself inside some
> role,
> that handles all the interfacing,
> and then hands over to the appropriate instance of <_function>?


Perhaps I'm misunderstanding you, but I'm wanting more generalized
behaviors in attributes which make life easier for programmers who wish to
use them. Building in tooling which is too specific for a particular use
case is something I'd like to avoid.

Best,
Ovid
--
Curtis "Ovid" Poe
--
CTO, All Around the World
World-class software development and consulting
https://allaroundtheworld.fr/
Re: Limitations of Attributes [ In reply to ]
On Wed, May 3, 2023 at 9:30?AM Branislav Zahradník <happy.barney@gmail.com>
wrote:


> just repeating my previous idea - what about `extends` for functions? eg:
>
> package Foo {
> sub SEARCH (... signature ...);
> }
>
> sub function :extends(&Foo::SEARCH) { ... }
>
> later extended signature support for setting fixed value (in opposite to
> default value) of parameter, eg:
>
> sub function :extends(&Foo::SEARCH) ($search_key := value = q (fixed
> value)) { ... }
>

I have similar thoughts about this as I mentioned to Ruud. Rather than
adding a specific-attribute for a particular use case, more generalized
behavior in attributes seems to be welcome. If we do that, something like
:extends could be built on top of it (though your signature syntax wouldn't
be valid and I think that would need to be a separate proposal.

Best,
Ovid
--
Curtis "Ovid" Poe
--
CTO, All Around the World
World-class software development and consulting
https://allaroundtheworld.fr/
Re: Limitations of Attributes [ In reply to ]
On 2023-05-03 17:36, Ovid wrote:
> On Wed, May 3, 2023 at 10:15?AM Ruud H.G. van Tol via perl5-porters
> <perl5-porters@perl.org> wrote:
>
> The set of instances of <function> could be implemented as
> a set of minimal instances called <_function>,
> and a single "wrapper" implementation of <function> itself inside
> some role,
> that handles all the interfacing,
> and then hands over to the appropriate instance of <_function>?
>
>
> Perhaps I'm misunderstanding you, but I'm wanting more generalized
> behaviors in attributes which make life easier for programmers who
> wish to use them. Building in tooling which is too specific for a
> particular use case is something I'd like to avoid.
>

ACK, I was probably over-assuming,
that there should be a clean separation possible
between the "interfacing" and the "functional" part/phase of the sub.

-- Ruud
Re: Limitations of Attributes [ In reply to ]
On Tue, 2 May 2023 14:33:04 -0500
Ovid <curtis.poe@gmail.com> wrote:

> Hi all,
>
> Attributes could really use a rethink in a number of ways and I'm
> curious if anyone has put any thought into this?
>
> For example, attributes in signatures are a syntax error:
>
> sub foo ($bar :some_attr) { ... }

Indeed - part of the next steps of signatures is to think about
attributes on them. Already folks have mentioned ideas like

sub f ($x :const) { ... } # assignments are forbidden
sub f ($x :alias) { ... } # assignments are visible to caller

--
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
Re: Limitations of Attributes [ In reply to ]
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
Re: Limitations of Attributes [ In reply to ]
On Fri, 5 May 2023 11:58:56 +0100
Dave Mitchell <davem@iabyn.com> wrote:

> 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.

A quick note on that part - the newly-added `method` keyword doesn't
allow you to rename the invocant variable at all. You just get `$self`,
so there's no such syntax ambiguity here to worry about.

--
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
Re: Limitations of Attributes [ In reply to ]
> A quick note on that part - the newly-added `method` keyword doesn't
> allow you to rename the invocant variable at all. You just get `$self`,
> so there's no such syntax ambiguity here to worry about.
>
>
If ever supported, it should be part of `class` syntax and not method
Every method of same class should use same name for `$self`


> --
> Paul "LeoNerd" Evans
>
> leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
> http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
>
Re: Limitations of Attributes [ In reply to ]
On Sat, May 6, 2023 at 7:41?AM Branislav Zahradník <happy.barney@gmail.com>
wrote:

> A quick note on that part - the newly-added `method` keyword doesn't
>> allow you to rename the invocant variable at all. You just get `$self`,
>> so there's no such syntax ambiguity here to worry about.
>>
>
> If ever supported, it should be part of `class` syntax and not method
> Every method of same class should use same name for `$self`
>

That's how it is implemented. method is part of the class/Corinna syntax
and the invocant name is always $self. I'm very happy to see that pain
point go away.

Best,
Ovid
Re: Limitations of Attributes [ In reply to ]
On Sun, 7 May 2023 at 12:16, Ovid <curtis.poe@gmail.com> wrote:

> On Sat, May 6, 2023 at 7:41?AM Branislav Zahradník <happy.barney@gmail.com>
> wrote:
>
>> A quick note on that part - the newly-added `method` keyword doesn't
>>> allow you to rename the invocant variable at all. You just get `$self`,
>>> so there's no such syntax ambiguity here to worry about.
>>>
>>
>> If ever supported, it should be part of `class` syntax and not method
>> Every method of same class should use same name for `$self`
>>
>
> That's how it is implemented. method is part of the class/Corinna syntax
> and the invocant name is always $self. I'm very happy to see that pain
> point go away.
>
>
OK, maybe bad wording again. I meant, when there will be possibility to
change `$self` into something else,
it should be same for every method in class. eg:

class :self($foo) FOO

Best,
> Ovid
>
Re: Limitations of Attributes [ In reply to ]
On Sun, May 7, 2023 at 3:15?PM Branislav Zahradník <happy.barney@gmail.com>
wrote:

>
> OK, maybe bad wording again. I meant, when there will be possibility to
> change `$self` into something else,
> it should be same for every method in class. eg:
>
> class :self($foo) FOO
>

My hope is that this won't happen any time soon. This provides no overall
benefit to the language and merely exists to provide an aesthetic benefit
to the handful of developers who prefer a different name.

However, we do not need any new attributes behavior implement this, so it's
kind of outside the scope of this thread (we'd potentially need new
behavior for the new class syntax to allow this kind of change, but it's an
extremely low priority and probably best avoided).

Best,
Ovid