roast
roast copied to clipboard
Require declarator on bare sigils
Many programmers put a lot of effort into eliminating global state or reducing it. For that to be easy, state has to be easily recognizable in code. Hidden state is the opposite of this, and Perl 6 lets one hide state "in plain sight", by providing single character state variables.
I suggest (for 6.d) to require state $
instead of the currently allowed bare $
, in line with my $
and named variables that also require an explicit declarator.
My apologies if this has already been discussed. The syntax of the bare sigil makes it rather hard to find any earlier conversations about the feature.
đź‘Ž đź‘Ž đź‘Ž on this. The beauty of the $
is how short it is to type. If you're gonna force use of state
my as well not have any anon state vars and force the user to write full names.
But what is the problem here exactly? $
comes very handy in one-liners, but does anybody use it often in real code (e.g. for modules or other bigger scripts)? And if yes, is it always unreadable/confusing?
From the docs:
In general, it is better style and p6ier to declare a named state variable in case you have to refer to it several times.
Apart from a weird “p6ier” word that needs to be changed, we can also make it say that sometimes declaring named state variables can improve readability (basically just remove “in case you have to refer to it several times”).
Would something like that work to resolve this issue? By the way, the docs already lightly discourage the use of $
by calling it “magical”.
anybody use it often in real code (e.g. for modules or other bigger scripts)?
I frequently use it as an iteration counter in loops. Doesn't look like I'm the only one: https://gist.github.com/32be65050b799c102282c8b0f55888f2 https://gist.github.com/Whateverable/48760806ce381aa2796379ed3ccf2d65 This search is fairly easy and probably catches 95% of use of these variables, which runs contrary to the claim in OP that these are hidden.
And if yes, is it always unreadable/confusing?
No, it's not confusing to me and it's one of the very first things I learned about Perl 6.
Many programmers put a lot of effort into eliminating global state or reducing it.
So let those programmers explicitly write state $
. Why force it on the rest of us?
I don't understand the comment about global state. I find it extremely unlikely you are creating global state via $
, since it's anonymous. No other pieces of code can touch it. It's usually local state (at least from I've seen and done), like @zoffixznet pointed out.
Replying to Alexdaniel:
$
comes very handy in one-liners
The same would be true for other implicitly declared variables. In Perl 5 oneliners, for example, it comes in handy that you don't have to type "our" for variables because "use strict" is not in effect by default.
but does anybody use it often in real code (e.g. for modules or other bigger scripts)?
Yes. I have used it by accident (fortunately in a way that broke things, so I found it fast enough) and others have indicated they use it on purpose.
And if yes, is it always unreadable/confusing?
In my opinion, it is definitely obscure and too easy to overlook. Like you said, the documentation lightly discourages it and calls it magical.
Replying to zoffixznet:
This search is fairly easy and probably catches 95% of use of these variables, which runs contrary to the claim in OP that these are hidden.
I never said or meant to imply that every single use was hidden. You may have not found the hidden (not really hidden, but "hidden in plain sight", that is: easily overlooked) instances. But grepping is also rather different from reading code. I believe that state should stand out visually, and that the nameless one-character state variables can cause code that will not be immediately obvious to many readers, including people who are aware the feature exists.
The beauty of the $ is how short it is to type. (...) Why force it on the rest of us?
I come from Perl 5. In Perl 5, many things are much shorter to type. The result of this is often called "line noise" and the feature of things being short to type is at least controversial, because often it hurts maintainability -- often because the readability is reduced.
When I was still more actively involved with Perl 6, it was the language design phase. Many of the magic and obscure features of Perl 5 were considered mistakes not to be repeated in the new language. Specifically, "huffman coding" was a big thing, as were design principles like "different things should look different" (or even "things that are alike should look alike"), and "the principle of the least surprise" (all paraphrased; the exact wording may differ). I feel strongly that this specific feature's syntax, with a single character to introduce a variable with an infinite lifetime, violates many of those principles.
Many nice and even useful features were taken away from you, and much extra typing to make things more explicit was forced on you. Why? Because it makes the language easier to learn and programs written in them easier to maintain. Most readers of code are new to the language or at least new to the code they're reading. And even if they have read it before, that may have been years ago.
Replying to vendethiel:
I don't understand the comment about global state.
I probably used the wrong name for this thing, since the word "global" is usually associated with scope. I used it in the sense of the term "global destruction" as it is used in Perl 5: the destruction of everything that still lives when the program in terminated.
It's state with infinite lifetime, and an extremely local scope. This kind of state is makes it harder to write functions that are re-entrant, and can easily lead to memory leaks. There are certainly many good use cases and I'm certainly not suggesting to remove the feature, I'm merely suggesting that they should be explicitly declared with a word that indicates what kind of variable it is.
@Juerd maybe you should start a style guide? People keep asking for a style guide for Perl 6, but the only thing we can direct them to is https://docs.perl6.org/language/traps (which is not a style guide, but it's a nice list of things you should be careful with). If you write it in a way that doesn't dictate strong opinions, we can probably even include it in perl 6 docs (for example, don't say not to use anon state vars, but feel free to suggest to consider explicit alternatives).
To clarify, my point is that we can keep a feature that a lot of people love, but at the same time give some light recommendations to make sure the feature is not abused mindlessly. Sounds like a win-win to me.
It's also possible to write a module that will enforce that style, to be used in git hooks.
In Perl 5, many things are much shorter to type. The result of this is often called "line noise"
That's contrary to my experience with both languages. Any time I switch from Perl 6 to Perl 5, I groan, because I have miles more of code to type. The line-noiseness of Perl 5 comes from its huge number of special cases and behavior, as its hard to remember all the exceptions unless you use the language regularly.
The $
construct is fairly unique. It has a trap with scoping and being thread-unsafe, but forcing the use of state
and parentheses will solve none of those problems, yet will add a bug with users writing state $
instead of $
's actual equivalent, which is (state $)
. This is exacerbated by state $++
actually doing The Right Thing, lulling the user into making an error when using a different construct where the parentheses change meaning.
It's state with infinite lifetime, and an extremely local scope
Are you sure it's infinite? Unlike Perl 5, we use reachability and not reference counting. If the block's clone is no longer reachable, wouldn't the objects stored in its statevars be GCed? I'm having trouble reproducing something that gets GCed with lexical vars, but doesn't get GCed with state vars. (you can use use nqp; nqp::force_gc; sleep 3;
at the end of the program to force a GC run).
When I was still more actively involved with Perl 6, it was the language design phase.
I feel like a lot of people never left that phase and we still get sweeping proposals to break fairly well-used features, by introducing bug-prone syntaxes, to achieve rather vague goals of unproven value.
It's state with infinite lifetime, and an extremely local scope.
Just a clarification: it's a state variable, and therefore it exists once per closure clone. Typical uses of it are in constructs like @foo.map({ $_ => $++ })
, and these are entirely threadsafe due to the per-closure semantics of state variables.
these are entirely threadsafe
Wasn't there something about creating the scalar or something that was the racy bit? IIRC it was the motivation behind https://github.com/rakudo/rakudo/commit/6af44f8d38a02bbd0d68cfd014165d6e33e4d89a where a useless statevar was changed to a lexical and that fixed part of crashes in threaded code. Excerpt from commit message:
Since we know that state variables have some racing issues
Also, would an object stored in such a state variable ever be GCed or would it remain until end of program, even if we'll never enter that closure clone again?