Compile-time checking of assignment to read-only variables (Re: MMD distances)
Carl M sak 18 May 2008 02:39:35
TSa (>):
sub bar ($x)
{
$x = 3; # error, $x is readonly
foo($x); # error, could hit rw Str
}
By the way, I hope it's possible to make the assignment `$x = 3` to the read-only variable $x a compile-time error.
In fact, I hope this to such a degree that I would like it to be part of a spec somewhere that a conforming Perl 6 compiler disallows assignments to read-only variables. I find nothing to this effect in S04 (but my grep-fu is imperfect, so I may just have missed it).
Pugs currently dies with a run-time error on this. Rakudo r27392 runs it fine and sets $x = 3 as if $x wasn't read-only.
By the way, I hope it's possible to make the assignment `$x = 3` to
the read-only variable $x a compile-time error.
I hope so, too. The variable and its read-only constraint is known at compile time and *not* dependend on the value inside. How it came in there in the first place is left to the runtime binding ;)
Regards, TSa. --
"The unavoidable price of reliability is simplicity" -- C.A.R. Hoare "Simplicity does not precede complexity, but follows it." -- A.J. Perlis 1 + 2 + 3 + 4 + ... = -1/12 -- Srinivasa Ramanujan
Patrick R. Michaud 9 May 2008 19:45:10 [ permanent link ]
On Fri, May 09, 2008 at 05:09:31PM +0200, Carl M sak wrote:
Pm (>):
In Rakudo's case, we just haven't implemented read-only traits
on variables yet.
Goodie. I guessed as much.
But yes, I expect that it will be caught as
a compile-time error.
And do you agree it's reasonable to expect this of every compiler?
Reasonable to expect it, yes -- but whether or not this rises to the level of being a "requirement in the spec" may be a different matter.
I could envision the possibility that some otherwise-very-capable Perl 6 implementation might be better served by having such checks performed at runtime (they have to be done there also) and leaving compile-time checking as an optimization. I suspect this is what Pugs did. Or an implementation might not have a clear-cut notion of "compile time".
So, as long as the assignment is properly prevented, I think that may be sufficient. (If the language designers decide otherwise, that's okay with me too.
And do you agree it's reasonable to expect this of every compiler?
Reasonable to expect it, yes -- but whether or not this rises to the
level of being a "requirement in the spec" may be a different matter.
I could envision the possibility that some otherwise-very-capable
Perl 6 implementation might be better served by having such checks
performed at runtime (they have to be done there also) and leaving
compile-time checking as an optimization. I suspect this is what
Pugs did. Or an implementation might not have a clear-cut notion
of "compile time".
So, as long as the assignment is properly prevented, I think that
may be sufficient. (If the language designers decide otherwise,
that's okay with me too.
I agree, to the extent that I understand your caveat. What we seem to agree on is that a compiler should disallow (obvious) assignments to read-only variables, provided that it is not compiler-architecturally unreasonable for it to do so.
The reason I think this is important is that I consider this feature low-hanging fruit. It should be the job of the compiler-writer to please the end-programmer as much as possible (in this case by not letting code through that will die at runtime). Similarly, it should (IMHO) be the job of the language designer to spec the ways in which a compiler can be expected to please the programmer.
Brandon S. Allbery KF8NH 15 May 2008 16:40:05 [ permanent link ]
On 2008 May 15, at 1:30, Me Here wrote:
"John M. Dlugosz" wrote:
no strong_type_check :rw
in scope can turn that off, in case you want to play dirty tricks.
What is the point of be able to mark things readonly if the compiler
does reject assignment attempts?
(assuming you meant "doesn't")
What is the point of marking things readonly if you can turn it off?
Documentation. Backward type-API compatibility.
I am unsure at this point if this applies to Perl 6, but in Haskell it is possible to do in-place update by diving into IO behind the scenes with (read-only by default) data structures. In this case "is ro" would be a reminder that the caller has expectations that you must be careful not to violate while you're working behind the curtain.
-- brandon s. allbery [solaris,freebsd,perl,pugs,haskell] allbery@kf8nh.com system administrator [openafs,heimdal,too many hats] allbery@ece.cmu.edu electrical and computer engineering, carnegie mellon university KF8NH
Brandon S. Allbery KF8NH 17 May 2008 18:04:27 [ permanent link ]
On 2008 May 17, at 4:10, Carl M sak wrote:
Whether we're risking the loss of important compiler optimizations by
allowing overriding of variable RO-ness is not for me to say, that's
up to the compiler writers around here. It seems to me you make it
sound worse than it really is, that optimizations can still be made in
many cases, and that a programmer who turns off RO stricture simply
takes a calculated risk.
The compiler should in fact assume that "is ro" is a hard fact; if the programmer chooses to override, on her own head be it. Examples using other existing languages: GHC doesn't compromise its optimization rules just because someone might be using unsafePerformIO (this is in fact quite similar as unsafePerformIO means a presumed read-only expression can vary at runtime) or unsafeCoerce#. gcc doesn't compromise its just because someone might use an asm() to do something naughty where the C / C++ layer can't see it. Etc.
I also came to think about this relevant quote from Jamie Zawinski:
Java is a remarkable example of how to do it wrong, for many values of "it".
-- brandon s. allbery [solaris,freebsd,perl,pugs,haskell] allbery@kf8nh.com system administrator [openafs,heimdal,too many hats] allbery@ece.cmu.edu electrical and computer engineering, carnegie mellon university KF8NH
] Oh, but it gets even better: it turns out they didn't really have to
] sneak in through native code anyway, at least as far as the JVM is
] concerned, since the JVM treats final variables as always writable
to ] the class they're defined in! There's no special case for
] constructors: they're just always writable. The javac compiler, on
] the other hand, pretends that they're only assignable once, either
in ] static init code for static finals or once per constructor for
] instance variables. It also will optimize access to finals, despite
] the fact that it's actually unsafe to do so.
I'm pleased to note that you made my point for me.
Sure, you can sneak in under the covers of the JVM and compromise the immutability of its final data. But you do have to sneak in. And when you do, and things go belly up in interesting ways, or worse continue to run but produce mysteriously wrong output, don't go running to blame either the Java spec or the JVM. Their writers made their optimisations, and the proofs of correctness of those optimisations, and proof of correctness of the entire system, based upon the specification of final. You hack it. Your problem.
But, if you add *is ro* to the P6 spec and then specify a way for users to ignore or turn it off, and you render it entirely worthless. Indeed it's worse than worthless because it is extra complication for no benefit. If it doesn't allow the compiler writeres to make any extra assumptions, it's just tying up space in symbol tables, consuming cycles in the parser, and most damningly, mindspace in the spec and users.
If you add it to the spec. Mean it. If you don't mean it, don't add it.
If you mean it, but it doesn't initially get implemented that's fine. Someday it might and someday we might benefit from it.
Add it to the spec whilst offering a way to ignore it and you've wasted everyones time.