my $pi is constant = 3;
Is this a special form? If yes, what does it desugar to?
my $pi is constant := 3;
my $pi is constant ::= 3;
If not a special form, should this work?
my $pi is constant;
$pi = 3;
If yes, should this pass compilation?
my $pi is constant;
$pi = 3 if (0|1).pick;
$pi = 4;
If not, should this work?
my ($x is constant, $y is constant) = (1, 2);
Thanks,
/Autrijus/
I believe any assignment to a declarator is potentially a special form,
or we can't get assignment to "has" and "state" to work right.
: If yes, what does it desugar to?
:
: my $pi is constant := 3;
: my $pi is constant ::= 3;
In this case it desugars to
my $pi is constant = 3;
:-)
In other words the assignment to a my turns into an ordinary assignment
that happens at runtime. Hopefully, since $pi is marked constant,
it could be optimized to a binding in many cases, but that's not the
semantics, and the difference shows up on objects pretending to be
values that have to be copied under assignment. If you don't want
a copy every time the "my" is instantiated you need to use := instead.
: If not a special form, should this work?
:
: my $pi is constant;
: $pi = 3;
That could be made to work by defining constant to mean you can assign
to it if it's undefined. But then it gets a little harder to reason
about it if $pi can later become undefined. I suppose we could
disallow undefine($pi) though.
: If yes, should this pass compilation?
:
: my $pi is constant;
: $pi = 3 if (0|1).pick;
: $pi = 4;
If it's a special form, it's a different special form from the assignment
case, and would have to revert to the allow-if-undefined semantics, which
is probably a halting problem for the compiler, and so would have to
defer to runtime to determine legality. But maybe that's a feature.
: If not, should this work?
:
: my ($x is constant, $y is constant) = (1, 2);
Under the assumption that only
my ($x,$y) is constant = (1, 2);
is the compile-time special form, the embedded is-constant declarations
would have to be turned into the run-time write-once checking kind of
declaration, if we allow those at all.
I suppose the late-binding view of reality is that all of these
are fundamentally run-time constraints on the second attempt to
set. where we can intuit some of those constraints at compile time.
I'm not sure what that view does to formal parameters though. Does it
mean that this is legal:
sub foo($a, ?$b) {
$b //= 2;
}
foo(1);
even though $b is not marked "rw" but is implicitly "constant"?
But maybe this would be illegal:
sub foo($a, ?$b = 42) {
$b //= 2; # compile-time error
}
foo(1);
on the theory that the = of the default construct is the same special
case as the = in
my $b is constant = 42;
Larry
Perhaps the actual rewrite is
my $pi is constant({ 3 });
much like
state $where = $California;
is desugared to
state $where is first({$California});
or some such, and
has $what = $tail;
is desugared to
has $what is build({$tail});
Then the form without the assignment:
my $what is constant;
can notice that it doesn't actually have a compile-time value and revert
to run-time checking, as discussed in my other response, presuming we decide
to support that mode.
Larry
Larry Wall wrote:
> In this case it desugars to
>
> my $pi is constant = 3;
>
> :-)
>
> In other words the assignment to a my turns into an ordinary assignment
> that happens at runtime. Hopefully, since $pi is marked constant,
> it could be optimized to a binding in many cases, but that's not the
> semantics, and the difference shows up on objects pretending to be
> values that have to be copied under assignment. If you don't want
> a copy every time the "my" is instantiated you need to use := instead.
Is it arguable to imagine the above beeing implemented by dispatching to
&infix:{'='}:(Item of Undef is constant, ::T.does(none(Undef) & Item)
--> ::T is constant)?
The Item of Undef is the return type of my and the is constant in the
return type prevents subsequent handling as lhs by standard targets of
&infix:{'='} or &infix:{':='} dispatches? Other mutator dispatches
like rw ref taking are excluded as well. To me it is a natural extension
of the concept of "interesting values of undef".
Constant value rapers/enchanters can of course still write non-standard
targets and I don't know how prospective victims/receivers can prevent
that fate/bliss. The German expression for what I mean here is
'Vergewohlwurstelung' which is a comprehension of
Vergewaltigung - rape, abuse
Wohltat - beneficence
wursteln - mess with the guts
Anyone know an english equivalent? I guess the concept is widespread
in the Perl community.
> : If not a special form, should this work?
> :
> : my $pi is constant;
> : $pi = 3;
>
> That could be made to work by defining constant to mean you can assign
> to it if it's undefined. But then it gets a little harder to reason
> about it if $pi can later become undefined. I suppose we could
> disallow undefine($pi) though.
Yep.
> : If yes, should this pass compilation?
> :
> : my $pi is constant;
> : $pi = 3 if (0|1).pick;
> : $pi = 4;
>
> If it's a special form, it's a different special form from the assignment
> case, and would have to revert to the allow-if-undefined semantics, which
> is probably a halting problem for the compiler, and so would have to
> defer to runtime to determine legality. But maybe that's a feature.
I dought that it's a halting problem. The (0|1).pick is just typed as
any(true,false) and as such renders the type of $pi after the respective
line as Int|Undef or Int^Undef which are both not applicable to
&infix:{'='}:(Item of Undef is constant, ::T.does(none(Undef) & Item)
--> ::T is constant)
This leads to $pi = 4 to fail at compile time if the set of possible
targets is closed at that time and contains no non-standard target.
Otherwise this check has to be defered to runtime.
> I'm not sure what that view does to formal parameters though. Does it
> mean that this is legal:
>
> sub foo($a, ?$b) {
> $b //= 2;
> }
> foo(1);
>
> even though $b is not marked "rw" but is implicitly "constant"?
Hmm, isn't the rw marking important to what happens to the callers
value that is bound to the formal parameters? Only an explicit
is constant trait constrains the inside on where the parameter can
be dispatched to.
> But maybe this would be illegal:
>
> sub foo($a, ?$b = 42) {
> $b //= 2; # compile-time error
> }
> foo(1);
>
> on the theory that the = of the default construct is the same special
> case as the = in
>
> my $b is constant = 42;
Only that ?$b is not marked is constant? Strange that is.
--
$TSa.greeting := "HaloO"; # mind the echo!
Straight out of the apocalypse--parameters default to constant.
Larry
However, I wonder if the intention was to replace the Perl 5 form of:
use constant PI => 3;
Which is a binding that happens at compile time. It'd be somewhat
strange if this dies with undef -- or even 'Str':
my Str $x is constant = 'foo';
BEGIN { die $x };
Or do you think that people should really write ::= for constants?
Thanks,
/Autrijus/
Hmm, well, we do need some form that is only temporarily constant for
this time through the elaboration and subsequent code. That is the
sense of "constant" we're applying formal parameters, after all.
So either we have to bifurcate the concept into "temporarily constant"
and "permanently constant", or we force people to distinguish with ::=
(or "is constant('foo')"), or we make some representations about the
requirement for the compiler to optimize the = form to:
my Str $x is constant('foo');
if the assigned value is "static" (much as we require the tailcall
optimization these days). So this would be another instance of
making the default semantics late binding, but optimized to earlier
binding in cases where it makes no semantic difference other than a
difference in run-time efficiency. Making this determination is
pretty much equivalent to constant folding.
Larry
Why isn't the late binding version
my Str $x is ro('foo');
In contrast to the 'is rw' trait? When I say 'is constant', can I be
rewarded for all my extra typing with some well-defined compile-time
optimization?
Ashley Winters
Autrijus Tang wrote:
> Or do you think that people should really write ::= for constants?
For me that is one option if I want the parser to recognize the
bareword pi and attach the same meaning as the literal 3.
We have at least
my ::pi ::= 3;
my enum <pi( 3)>; # I hope the whitespace doesn't hurt
my macro pi { 3 };
my &pi = { 3 };
BTW, are all these competing for the same name slot or can
some or all exist in parallel? Can they if the type is the
same but not for
my ::pi ::= 1;
my enum <pi( 2)>;
my macro pi { 3 };
my &pi = { 4 };
The form
my $pi is constant = 3;
to me bears the disadvantage, that it doesn't look like a
constant at the use site
$yi = $pi++ + $xi; # error can't modify $pi
where I would oblige me to know more about bare pi then $pi.
The latter obviously is a variable. The return value of pi
is not so obvious.
In an interface definition however
sub foo( $pi is constant ) {...}
tells the prospective caller that her arguments are
not messed about with. What the inside does with the
local copy is at least not of interest to the caller.
But to the optimizer. Thus Perl6 also has the form
sub foo( $pi is copy ) {...}
right? The crux is what shall
sub foo( $pi ) {...}
default to. With a relatively cheap COW backend I would
prefer 'is copy'.
Enjoy my silence for the next two weeks.
I'll be offline at least that long.
I think "ro" is ugly and impenetrable and too easy to mistake for
"rw". But if we're actually going to have a different lifetime
on the info, it isn't really a "my", and we should probably have a
different declarator:
constant Str $x = 'foo';
That would scope the name like "my", but alias a permanent location
like "our", except that the permanent location is also immutable.
It can have its own '=' desugaring separate from "my", and "my"
stays a run-time assignment in the abstract. (It's not entirely clear
whether constant should desugar to begin() or init() though...)
If we have that, then maybe "is constant" is confusing for the other
meaning, and we can change it to "is readonly", which then becomes
the default for formal parameters, so you'll almost never see it,
and it's okay for it to be huffmanly long, and violate the "perfect
language" aspects of rw/ro. On the other hand, it's possible I could
be argued into "ro", by the similar argument that you'll almost never
see it.
Larry
Maybe it's now
constant num pi = 3;
: BTW, are all these competing for the same name slot or can
: some or all exist in parallel? Can they if the type is the
: same but not for
:
: my ::pi ::= 1;
That's in the type namespace, which is to say, package/module/class namespace.
: my enum <pi( 2)>;
Whether that ends up in type namespace or function namespace depends on
how far we stretch the subtype metaphor. The Apocalypse has it as a subtype.
: my macro pi { 3 };
: my &pi = { 4 };
Those both live in the function namespace, as would the new constant
declarator if we include the sigilless form above .
: The form
:
: my $pi is constant = 3;
:
: to me bears the disadvantage, that it doesn't look like a
: constant at the use site
:
: $yi = $pi++ + $xi; # error can't modify $pi
:
: where I would oblige me to know more about bare pi then $pi.
: The latter obviously is a variable. The return value of pi
: is not so obvious.
Yes, and there's little need to require the $ anymore for interpolation
since you can always say {pi} for that.
: In an interface definition however
:
: sub foo( $pi is constant ) {...}
:
: tells the prospective caller that her arguments are
: not messed about with. What the inside does with the
: local copy is at least not of interest to the caller.
: But to the optimizer. Thus Perl6 also has the form
:
: sub foo( $pi is copy ) {...}
:
: right? The crux is what shall
:
: sub foo( $pi ) {...}
:
: default to. With a relatively cheap COW backend I would
: prefer 'is copy'.
That's something we could relax later if COW becomes ubiquitous, but
the conservative way forward is to disallow writes in the function body
for now. But you're right that the caller doesn't care which way that's
done.
: Enjoy my silence for the next two weeks.
: I'll be offline at least that long.
Have the appropriate amount of fun. :-)
Larry
Which would basically throw away compile-time optimizations relating to
constants wouldn't it?
Adam K
You could still reason about it if you can determine what the initial
value is going to be. But certainly that's not a guarantee, which
is one of the reasons we're now calling this write/bind-once behavior
"readonly" and moving true constants to a separate declarator:
my $pi is readonly;
$pi = 3;
vs
constant $pi = 3;
or
constant Num pi = 3;
or if you like, even
constant π = 3;
Larry
If you can assign it when it contains an undefined value, bad
things happen:
sub f ($x is readonly) { $x = 10 }
my $a; f($a);
Compare this with:
my $x is readonly;
$x = 10;
If it is defined as "bound to a immutable value cell", both cases
above would fail, which is imho the easiest to explain.
> You could still reason about it if you can determine what the initial
> value is going to be. But certainly that's not a guarantee, which
> is one of the reasons we're now calling this write/bind-once behavior
> "readonly" and moving true constants to a separate declarator:
>
> my $pi is readonly;
> $pi = 3;
The question remains, whether you can bind the readonliness away:
my $pi is readonly; # undef at this point
my $e is rw = 2.7;
$pi := $e;
$pi = 9;
I can argue both sides -- rebindable is easier to implement, but
non-rebindable is perhaps more intuitive.
Thanks,
/Autrijus/
Minor detail: when does the right side get evaluated? That is, what
happens here:
constant pi = make_pi();
sub make_pi() { 4*atan2(1,1) }
If you want this to succeed, then this must fail:
constant pi = 4*atan2(1,1);
BEGIN { say "pi = {pi}" }
Is it even possible to evaluate constants at CHECK time and then
constant-fold them in before the program is run?
Luke
Though I think most people have a pretty good understanding of "worm"
these days, what with CD and DVD burners...
"Darn, I turned my third parameter into a coaster. Now what am I gonna do?"
: > You could still reason about it if you can determine what the initial
: > value is going to be. But certainly that's not a guarantee, which
: > is one of the reasons we're now calling this write/bind-once behavior
: > "readonly" and moving true constants to a separate declarator:
: >
: > my $pi is readonly;
: > $pi = 3;
:
: The question remains, whether you can bind the readonliness away:
:
: my $pi is readonly; # undef at this point
: my $e is rw = 2.7;
: $pi := $e;
: $pi = 9;
:
: I can argue both sides -- rebindable is easier to implement, but
: non-rebindable is perhaps more intuitive.
English has a long history of hoisting the adjectives from the object
to its container. "I'd like a nice cup of tea" and such. So in general
I think people will expect a readonly variable to contain a readonly
value, and maybe we should do the extra work to enforce that transitively.
That being said, there's also a history of rebinding references, as
in "That woman is a man!" But we intuitively recognize that there's
something funny going on there linguistically. We can deal with it
as humans, but maybe we can allow the soulless computer to throw a
exception on such contradiction instead of laughing like we do.
That being said, it's still quite possible that
my $pi is readonly;
realizes that it's not bound to anything reasonable yet, and set
up a "worm" container of some sort that binds lazily at run time.
As with parameter defaults, it's more about whether the container's
value exists than whether it's defined.
Larry
That should fail, I think. Constant pseudo assignment is equivalent to
"is begin(make_pi())", in the same way that other pseudo-assignments
pay attention to the declarator to figure out when they really run.
And I think we want constants lexically scoped and known to the
compiler so it can do immediate constant folding. This also has the
nice property that it visually distinguishes values intended for
consumption by the compiler from values intended for consumption for
the runtime.
: If you want this to succeed, then this must fail:
:
: constant pi = 4*atan2(1,1);
: BEGIN { say "pi = {pi}" }
That one succeeds.
: Is it even possible to evaluate constants at CHECK time and then
: constant-fold them in before the program is run?
I think that sort of chicanery is best left for
sub pi() {...}
say "pi = {pi}";
sub pi() { 4*atan2(1,1) };
Larry
--
Mark Biggar
ma...@biggar.org
mark.a...@comcast.net
mbi...@paypal.com> On Wed, Aug 17, 2005 at 08:47:18AM -0700, Larry Wall wrote:
> > : >That could be made to work by defining constant to mean you can assign
> > : >to it if it's undefined. But then it gets a little harder to reason
> > : >about it if $pi can later become undefined. I suppose we could
> > : >disallow undefine($pi) though.
>
> If you can assign it when it contains an undefined value, bad
> things happen:
>
> sub f ($x is readonly) { $x = 10 }
> my $a; f($a);
>
> Compare this with:
>
> my $x is readonly;
> $x = 10;
>
> If it is defined as "bound to a immutable value cell", both cases
> above would fail, which is imho the easiest to explain.
Not only that, but what if what I want is a named constnat undef value?
> On Wed, Aug 17, 2005 at 08:47:18AM -0700, Larry Wall wrote:
> > : >That could be made to work by defining constant to mean you can assign
> > : >to it if it's undefined. But then it gets a little harder to reason
> > : >about it if $pi can later become undefined. I suppose we could
> > : >disallow undefine($pi) though.
>
> If you can assign it when it contains an undefined value, bad
> things happen:
>
> sub f ($x is readonly) { $x = 10 }
> my $a; f($a);
>
> Compare this with:
>
> my $x is readonly;
> $x = 10;
>
> If it is defined as "bound to a immutable value cell", both cases
> above would fail, which is imho the easiest to explain.
>
> > You could still reason about it if you can determine what the initial
> > value is going to be. But certainly that's not a guarantee, which
> > is one of the reasons we're now calling this write/bind-once behavior
> > "readonly" and moving true constants to a separate declarator:
> >
> > my $pi is readonly;
> > $pi = 3;
>
> The question remains, whether you can bind the readonliness away:
>
> my $pi is readonly; # undef at this point
> my $e is rw = 2.7;
> $pi := $e;
> $pi = 9;
>
> I can argue both sides -- rebindable is easier to implement, but
> non-rebindable is perhaps more intuitive.
>
> Thanks,
> /Autrijus/
>
OK, so then there is not "is constant" at all... just "is readonly"?
Makes a lot more sense to me.
Adam
If we went with "bind once" rather than "write once" semantics then after
my $foo is readonly := undef;
$foo could not be rebound, but saying
my $foo is readonly;
$foo := bar();
could still be made to work. But that means that $foo *as a container*
would have to remember if its value "exists" rather than relying on
the value itself knowing if it's defined. (But that's essentially
the same distinction we make for defaults in signatures: if you pass
undef as an argument, it doesn't trigger default setting.)
In other words, you could desugar
sub foo ($a = 1) {...}
to
sub foo ($a) {
$a = 1 unless exists $a;
...
}
Larry
I like this. Can we go for it, at least for this week? :)
Thanks,
/Autrijus/
Sure. Though it probably also wants to stay as metadata associated
with the signature, since part of the reason for putting it in
the signature in the first place is so that optimizers can install
constants on the caller end, at least for ordinary sub calls. Also,
desugaring a predeclaration would tend to cloak the yadae at the end,
but maybe that's not a problem unless you use the presence of bare
yadae in the body to suppress redefinition warnings.
Larry
I think in general the only time you're allowed to monkey with the
symbol table is when you're compiling, so deletions could just fall into
that category. The compiler has to be able to depend on its symbols
not going away once it's done.
Larry
The full desugared form is, I think:
our &foo; # lifted to beginning of package!
...
BEGIN {
&foo := a Sub is stub {
($a) := &?Internals::GETARGS();
$a = 1 unless exists $a;
# real body begins here
...
};
}
with the "is stub" -- not neccessarily exposed to the user level --
filled in by a parser rule, i.e. a predefined macro.
Does this sound sane?
Thanks,
/Autrijus/
No, but it sounds least insane. :-)
Larry
Er, sorry, the ($a) would need a my() scope identifier, as with all
parameters and hoisted mid-block my() declarations.
Also, "a Sub" should read "a sub".
Thanks,
/Autrijus/