Front page | perl.perl5.porters |
Postings from November 2019
Miscellaneous suggestions
From:
Dave Mitchell
Date:
November 28, 2019 17:07
Subject:
Miscellaneous suggestions
Message ID:
20191128170621.GH3573@iabyn.com
=head2 Synopsis:
sub foo (
Dog $spot, # same as my Dog $spot
$x ||= $default, # use default value if arg is missing or false
$x //= $default, # use default value if arg is missing or undef
$foo?, # short for $foo = undef
\@bar?, # short for \@bar = []
\%baz?, # short for \%baz = {}
) { ...}
bar(=$x, =$y); # short for bar(x => $x, y => $y)
Here are a few random suggestions that people have made at various times
(or that I thought up all by myself!).
=head2 Defined-or
in [perl #132444], Ovid suggested
sub f($x //= expr) { ... }
which is like
sub f($x = expr) { ... }
Except that it uses the default expression if the argument is undef as
well as if it is missing.
Presumably we should also have ||= .
=head2 Allow typed variables.
See the big proposal for a constraint system. Part of that proposal is that
the syntactic slot for types (similar to 'my Foo $foo') shouldn't be used
for a constraint (that becomes ($x is Foo) or ($x isa Foo) instead).
So I propose we allow
sub f(Dog $spot, ...) { ..}
and make it mean exactly mean the same as the currently supported
my Dog $spot;
which (among other things) allows compile-and runtime checking of
subscripts of hash references. If the semantics of 'my Dog $spot' ever
expand in the future, then the meaning of 'sub f (Dog $spot)' expands in
lockstep.
Placeholder parameters wouldn't be allowed types.
=head2 Allow a shortcut for a 'default' default value
allow $foo? as a shortcut for $foo=undef
and $? as a shortcut for $=
Similarly for reference aliases,
\$s? becomes a shortcut for \$s = undef,
\@a? becomes a shortcut for \@a = [],
\%h? becomes a shortcut for \%h = {},
At the same time, ban the existing legal syntax '$=' which means an
optional placeholder, and allow only the new '$?'. This would make things
more consistent, as '$foo=' is currently illegal. Also, I find a bare
trailing equals sign ugly, and it could potentially clash with future
syntax which might be added to the end of a parameter.
Note that ?$foo is a query parameter "borrowing" the next argument, while
$foo? is an optional parameter which is assigned an undef value if no
argument is present.
=head2 Auto-declare $self
Perhaps allow simple syntax to auto-declare $self as the first argument?
In Perl 6, the invocant is implicit in method subs, and can be accessed
using the 'self' keyword:
method foo ($x) { self.do($x, 'foo') }
but can be explicitly named (note the lack of comma):
method foo ($me: $x) { $me.do($x, 'foo') }
Cperl supports a similar auto-declaration with an added 'method' keyword:
method foo () { $self->{foo} }
method bar ($this:, $x) { $this->{$x} }
Perl 5 of course doesn't have a 'method' keyword, and if we were to add
it, we would need to decide what semantics it brought to the table.
I don't have any strong urge to add such a feature.
=head2 Allow a code block
Using the general query parameter escape mechanism (which doesn't consume
an argument), perhaps a parameter starting with '?{' could be a code block
which would be executed at that point in the argument processing. E.g.
sub foo($x, ?{ print "x=$x\n" }, $y = $x+1) { ... }
(The docs will need to warn that it may affect (as in remove) optimisation
of subsequent parameter processing.)
I suppose the question is, whether this is useful, and whether it allows
you to do things that can't be done with default value expressions, with
the proposed $x //= 0 'undef parameter' handling, and with the proposed
constraint syntax (where/as etc)?
The '?' before the '{' isn't strictly necessary syntax-wise, but grouping
it in with the 'query parameter' syntax emphasises that this parameter
doesn't consume an argument.
=head2 Whitespace
We need to decide where whitespace is allowed or forbidden in things
like
??$foo
:\@bar=[]
etc.
My feeling (and as expressed in other individual proposals here) is that
everything apart from the sigil and parameter name is signature syntax and
can have optional whitespace around it, like perl stuff generally can.
E.g. both these are allowed:
Dog\:$foo:shared=0 is Int where$_>0
Dog \ : $foo : shared = 0 is Int where $_ > 0
Similarly, both of these are ok:
??$has_x
? ? $has_x
The remaining issue is whether whitespace is allowed between a sigil and a
parameter name. Perl 5 currently allows:
my $ x;
my $
y;
and similarly allows:
sub f ($ x, $
y)
{ ... }
On the other hand, Perl 6 doesn't allow whitespace. Should we similarly
ban it from Perl 5 signatures? My gut feeling is yes: fix this while still
experimental.
=head2 Other traits
(This section is just a vague bit of hand-waving.)
The current Constraints proposal defines 4 traits which can follow a
parameter declaration (an attribute and a default value have been included
jn theses examples to demonstrate where traits fit in with them):
$x :shared = 0 where ...
$x :shared = 0 as ...
$x :shared = 0 isa ...
$x :shared = 0 is ...
Should we in some fashion allow additional user/pragma defined traits?
E.g. 'does', 'has' etc? I have absolutely no idea of how they could be
hooked in (or even whether they could), or how useful they would be, or
what they (in general terms) would do.
Also, is the existing attribute mechanism sufficient instead? The main
differences are that:
1. Attributes take simple q()-quoted strings as their argument, and
are called immediately after the parameter lexical variable has been
created but before the argument has been processed and bound to the
parameter.
2. The currently proposed constraint traits are processed after argument
and/or default value binding, and what follows them is general perl
syntax, at a precedence such that only a ',', ')' or another trait
can terminate them. In addition, the complete collection of trait
code is enclosed in a logical scope where $_ has been initially
aliased to the parameter variable. Presumably custom traits would
follow a similar pattern.
=head2 Order of features within a parameter declaration
I propose the following order:
? Optional start of query parameter
? Optional start of boolean query parameter (??$x)
Int Optional type
'\' or '*' Aliasing
: Named parameter
[$@%]foo Sigil with optional parameter name
! Optional "croak if undef"
:foo(...) Optional attribute(s)
? 'default' default value (instead of default value below)
= .... Default value
where/as/isa/is ... Constraint
=head2 Duplicate parameter names should be an error
At the moment, this just gives a warning:
sub f ($a,$a) { ... }
"my" variable $a masks earlier declaration in same scope
I think it should croak instead. (p5hack agreed).
=head2 Signature introspection API.
It has been suggested that there should be a Signature Introspection API
(possibly via a CPAN XS module) which say, given a code ref, allows perl
code to return information about the sub's signature declaration.
Should perl supply such an API? Failing that, should perl make it easy
(e.g. by guaranteeing a stable optree layout) for a 3rd party to provide
such an API? Or should we declare that this is A Bad Thing - that the
signature is private implementation detail of a sub which it's free to
change, and that external code inspecting is wrong. In which case we would
offer no support or guarantees to anything attempting to implement such an
API.
IIRC Aaron Crane has been championing this, and that in a moment of
weakness I may have encouraged him (or at least not discouraged him).
Now from a more sober standpoint, I'm reverting to my usual gut feeling
that we shouldn't provide guarantees about opcodes etc.
=head2 Caller parameter name auto-generation
(This isn't strictly speaking a proposal about signatures.)
When passing named parameters, you often end up passing both a name and
a variable with that same name:
sub foo(:$x, :$y) { print $x + $y }
my ($x, $y) = ....;
foo(x => $x, y => $y); # 'x' and 'y' appear twice in the source
Perl 6 has a bit of syntactic sugar which allows you to avoid repeating
yourself:
foo(:$x, :$y);
is short for
foo(x => $x, y => $y)
It would be nice if Perl 5 provided a similar syntax. In fact this
wouldn't just apply to sub calls, it could be used anywhere in list
context, e.g.
%hash = (:$x, :$y);
It would be a compile-time error in void/scalar context. Unknown context
would be treated as list context, so e.g. these
return :$y;
return :$x, :$y;
would be compiled respectively as
return y => $y;
return x => $x, y => $y;
and if that sub was called in scalar context, the sub would return just
the last element, ie. $y.
Of course, the specific syntax ':$x' wont work in Perl 5, as it's seen as
part of a ? : conditional. In fact most punctuation characters appearing
before a sigil already have some sort of meaning in Perl 5. These appear
to be free still (at least in the context of when a term is expected):
^$x
=$x
>$x
.$x
A second possibility is some sort of punctuation char between the sigil
and variable name, e.g. $*foo. Most of the time this currently gets parsed
as a special punctuation variable followed immediately by a barewword.
Possibly the lexer's behaviour could be changed so that a specific
punctuation var followed immediately by a bareword would be treated
specially. This then gives lots of possibilities, e.g.
$!x
$"x
etc. However, personally I prefer the special char being before the sigil,
and of the four listed above I think I prefer '='. So that's
foo(=$x, =$y);
%points = (=$x, =$y);
etc.
Whitespace should be allowed:
@points = (= $x, = $y);
Note that it would be a parse error for '=' to precede anything other than
a plain scalar lexical or package variable name. So these are legal:
= $foo
= $1
= ${^FOO} # same as "^FOO" => ${^FOO} # or should this be illegal?
= $Foo::Bar # or should this be illegal?
while these are illegal:
= @foo
= $foo[1]
Although arguably
=@foo
=%foo
could be shorthand for
foo => \@foo
foo => \%foo
(I'm not entirely convinced, though).