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