develooper Front page | perl.perl5.porters | Postings from February 2015

Re: [perl #123069] signature/attribute syntax is awful

Thread Previous | Thread Next
From:
Lukas Mai
Date:
February 24, 2015 20:42
Subject:
Re: [perl #123069] signature/attribute syntax is awful
Message ID:
54ECE235.8040207@gmail.com
Am 24.02.2015 um 17:43 schrieb Zefram:
> l.mai@web.de wrote:
>> The syntax 'sub foo :attributes ($signature) { ... }' is awful. It
>> should be 'sub foo($signature) :attributes { ... }'. (This might be a
>> candidate for bug #121481.)
>
> I do not approve of this change.  It gives the misleading impression
> that the signature is metadata that could reasonably be examined by
> distant code.

1) But it is! Function::Parameters provides an introspection interface, 
and there's no reason we couldn't add one to core perl.

2) I don't understand what this syntax change has to do with introspection.


>> Why? Because syntactically the signature replaces what used to be the
>> prototype, and that comes before attributes.
>
> It only `replaces' prototype syntax in the sense that there is a syntactic
> clash between them that we have resolved by having the signature-syntax
> feature flag also disable prototype syntax.  It is not a replacement in
> the sense of any semantic substitutability: signatures and prototypes
> address different aspects of subroutines, neither can do what the other
> does, and neither makes the other irrelevant.  It is perfectly sensible
> for a subroutine to have both.
>
> Nor was it a priori necessary that enabling signature syntax would disable
> the short prototype syntax; recall the "simple signatures" that I did
> before the present signatures, which allowed "sub ($$) ($foo, $bar) { }".
> It is not at all necessary that syntactically clashing alternatives fill
> exactly the same syntactic slot.  A lot of Peter Martini's signature
> patches suffered terribly from this preconceived notion that signatures
> had to occupy precisely the syntactic slot of prototypes.

It's the other way around: Prototypes have (for a long time) occupied 
the syntactic slot of parameter lists.
(Aside: I strongly dislike the term "signatures" for what amounts to 
simple parameter lists. If anything, the name "signature" is what 
suggests introspectability from outside.)
They were always meant as a stop-gap measure, to be replaced by actual 
parameter lists. Quoting perlsub: "Some folks would prefer full 
alphanumeric prototypes. Alphanumerics have been intentionally left out 
of prototypes for the express purpose of someday in the future adding 
named, formal parameters."

Perl borrows most of its general syntactic structure from C. All 
languages descended from C (as well as many others) use something like 
"function-keyword NAME(PARAMS) ..." for defining functions. I think 
there's a reason for that, and that reason is that declaration mirrors 
use. I.e. if you look at a call site like

   foo(42, $user, "note");

and then at the definition of foo

   sub foo($id, $name, $category) {

you can immediately tell what's what: 42 is the id, $user is the name, 
"note" is the category. I don't have to scan down into the function 
body, and I don't have to skip over any attributes. "foo(...)" forms a unit.

(It's not just C-like languages either. Scheme does the exact same 
thing, modulo calling syntax:

   (foo 42 user "note")  ; call
   (define (foo id name category) ...)  ; definition
)

>
> The perpetuation of this misunderstanding of signatures as a funny kind
> of prototype is rather making me regret implementing signature syntax.
> I'm still satisfied at having forestalled some really terrible patches
> that were in danger of being accepted, but perhaps I should have demanded
> that we find non-clashing syntax, or some way of resolving the clash
> that doesn't disable the short prototype syntax.

But prototypes were documented as a funny kind of parameter list?

>> It's also what perl itself does in C. :-)
>>
>>   OP* Perl_newDEFSVOP(pTHX) __attribute__((warn_unused_result));
>
> Utterly irrelevant, because of fundamental differences between the
> two languages.  C's parenthesised formal parameter list, which in a
> declaration is actually called the "prototype", *is* metadata that must
> be declared before call sites can be compiled, so has just about the same
> status as gcc's attributes.  Comparing to Perl, the C prototype is more
> akin to a Perl prototype than to a Perl signature.  Though in a function
> definition (as opposed to declaration) the formal parameter list fulfills
> both roles, which would be akin to a Perl signature implying a prototype.
> If we had implemented such an implication, then it *would* have been
> reasonable to allow a sub declaration with signature, just in order to
> get the implied prototype.  The general unpopularity of prototypes in
> Perl ruled out us implementing that kind of implication.
>
> Ultimately, gcc's placement of the attribute clause in the syntax is an
> arbitrary choice.

Arbitrary only as far as the compiler is concerned. Grouping expressions 
with () instead of, say, )( or (] is also "arbitrary". It's just what 
people expect.

Consider the following variants:

1) __attribute__((warn_unused_result)) OP* Perl_newDEFSVOP(pTHX);
Attributes precede a normal C declaration. This seems OK.

2) OP* Perl_newDEFSVOP(pTHX) __attribute__((warn_unused_result));
Attributes follow a normal C declaration (sort of like an afterthought). 
Also OK.

3) OP* __attribute__((warn_unused_result)) Perl_newDEFSVOP(pTHX);
Attributes precede the function name, isolating it from the return type 
and making it hard to find the name being declared. Very questionable.

4) OP* Perl_newDEFSVOP __attribute__((warn_unused_result)) (pTHX);
Attributes follow the function name, isolating it from the parameter 
list (similar to #3). This makes it harder to visually isolate the 
parameter list. Ew :-(

5.a) OP __attribute__((warn_unused_result))* Perl_newDEFSVOP(pTHX);
5.b) OP* Perl_newDEFSVOP(__attribute__((warn_unused_result))pTHX);
NO.

Personally I find #1 and #2 most "logical" or readable, and I'm pretty 
sure I'm not alone.

Roughly analogous to #4 in Perl:
sub index :method Chained('wiki') Args(1) ActionClass('Foo') ($c, $id) {
   ...
}

This looks so bad I don't even know where to start.

-- 
Lukas Mai <plokinom@gmail.com>

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