develooper Front page | perl.perl5.porters | Postings from March 2021

Re: on changing perl's behavior

Thread Previous | Thread Next
From:
Ricardo Signes
Date:
March 30, 2021 03:08
Subject:
Re: on changing perl's behavior
Message ID:
3d6f10ab-7c92-4daa-ad86-dab8945abb54@dogfood.fastmail.com
On Sat, Mar 27, 2021, at 4:49 PM, Ricardo Signes wrote:
> So I think, after saying all this, the first big question is:  Is there a general agreement that there are kinds of changes we've made (or will make) to the language that we can ease into making the default, through some multi-step process?  We may need to hash out individual changes' paths forward, but if there is an overwhelming opposition to changing these sorts of defaults *at all*, then I think a lot of this conversation has to be entirely reconsidered.

I don't think we've had enough responses, especially from core team members, to say we have some kind of clear consensus.  But that's fine with me, and basically expected.  So I'm just going to try to keep moving forward on the topic.  (I would, of course, love to hear some chiming-in from more of the core team, too, though!)

Of those who responded, I think there is *generally* an agreement that sometimes changing defaults in the language is justified.  There's also not a lot of agreement that any existing feature-guarded feature is worth the trouble.

So, I want to go through a bit of what *I* know are some of the good and bad things going on here.  All of these are part of a big complicated set of trade-offs.  I am not suggesting that any of these is a single guiding principle to be followed as the ultimate concern.  Also, I get it.  This list is both long *and* incomplete, which is an obnoxious combination.  Still, I think it's worth putting it down:
 * Needing to writing boilerplate to get a good programming language is bad.  The more you have to write, the worse.  The least you might have to write is *nothing*.  That would be best.  The second least you might have to write is "use vX;".  Anything less than "use vX;" but more than nothing is just golf.
 * Needing to edit your source code when you upgrade from one version of the language to another is bad.  The more you have to edit, the worse.  The smallest likely edit is to add "use vY;" at the top.  Not every change can be like that.  When $* went away, adding "use v4" was not going to help.
 * Getting advance notice that your program is going to break in the future is good.  The ideal length long enough that you see warnings when you upgrade telling you that things will be broken in your next upgrade.  (Astute readers will realize that this is a pretty hard target to actually guess at.)
 * When "your program will break" notices are given, it's good when it can tell you how long you have (largely, I think, as a motivator!) and specifically how to fix your problem.
 * Needing to edit *somebody else's* source code when you upgrade from one version of the language to another is bad, and specifically worse than having to edit your own.  There are pieces of software on the CPAN that haven't been updated for years, but run fine.  If you rely on them, and they break, and they have no clear maintainer, you have a new problem.
 * Finding out that code samples in the documentation you're looking at no longer work because the language has moved on is bad.  It's another form of "needing to edit somebody else's source code", but if we're talking about a printed book, "patches welcome" is not really applicable.
 * Making Perl harder to parse is bad.  When perl is parsing Perl, it knows what kind of semantics are in play.  Other things, like PPI or perl.vim, do not.  They already suffer because of the many ways that Perl's execution can alter parse semantics.  Making Perl harder to parse makes it less likely that we get good tools for working with Perl documents.
 * Making Perl easier to parse is good.  This is not the same as the previous point!  Consider the ambiguity between "sub foo ($) {...}" whether prototypes or signatures are enabled.  Determining the enabled-ness of signatures statically is a fool's errand.  Because writing boilerplate is bad, there exist numerous helper pragmata <https://metacpan.org/pod/rjbs> that turn on a bunch of features, warnings, and so on all at once.  The static analyzer won't see this.  Having fewer options, rather than more, makes Perl easier to parse — if you write off parsing old documents.
 * This one I think I can only state as a trade-off per se:  Spending time on maintaining long-discouraged behaviors is good only to the extent that they can't be deprecated and removed instead.  How do we know whether we can deprecate and remove some behavior?  Well, that's largely a function of all of the above.

I'll stop this list there.  I'm sure it's not complete, but it's long enough, contains at least most of what I'm thinking about, and also it's getting late here.

[ At this point I wrote a few paragraphs, deleted them, decided I was too tired, and went to bed.  Now it's morning and I'm picking back up. ]

I think a lot of the above circles around the idea that what we want is to feel like everyone has one Perl, and that it's the best one we can provide.  Since there is already more than one Perl (for example, "default feature bundle" perl and "use v5.32 perl"), the question is how (and whether) we can resolve that.

One way to do it is to gradually alter the default to continue to approach the current best practice, dropping old behaviors from the default bundle, possibly replacing them with new ones.  The way I imagine this is that right now, we have a window of "best Perls" that have existed.  It was originally defined with two values: one close to v5.8's behavior, one with the v5.10 behavior.  Then, every few years, we have been adding new values "at the right", defining the "best Perl" for each new version.  At the same time, we've been minimally shaving off bits at the left, with the most notable example probably being dropping the "arybase" feature.

There are at least a few futures that have been discussed:

1.  The default bundle is always the most-compatible-with-v5.8 bundle.  (This is our current reality.)
2. The default bundle is occasionally reset to point to a recent version.  Some of the warning for this is "warnings" and some is just in the release notes.
3.  The default bundle is continuously trailing behind "the best," trying to target a recent version of what is best while also warn-ing about the changes to the default bundle in the next release.

These second two futures are built with heavy investment in the difference between typing boilerplate and no boilerplate.  We already have a means to say "get the best Perl you can get," and it's something like:
use v5.32.0; use warnings; use utf8; no feature 'switch';
use if $USER eq 'rjbs',
  experimental => qw(const_attr declared_refs refaliasing re_strict regex_sets signatures);

Even that first line is a bunch.  Plausibly, it can all be boiled down to "use vX;" with a bit of doing.  Then we get into the space between boilerplate being "use vX" and being nothing.

One question here is "what are the costs incurred by changing the default group", and that ground has been trod a lot, and I think we should tread it some more, but for now I want to put it aside.  The other question is:  Who benefits from "boilerplate zero" and how?

I think it's something like this:

*People writing new code *get benefits from writing "no boilerplate" code.  They just start writing, they don't need to remember the correct invocation, and the documentation shipped with their Perl is written for the common case being "you are using default Perl, so we never need to show any governing pragmas."  Of course, "don't have to remember the invocation" begs the question.  Did they have to before?  No, but the invocations get them:  typo protection, catching probable (or possible) errors, using the most-likely (says me) encoding for their source document, and turning on features that they're likely going to want.  A lot of it is footgun removal.

On the other hand, in many case, people who write new code turn into people with old code to maintain.  Later, that code may run up against changes in defaults in a later version.  It won't include "use vX" — the avoidance of which was the whole point — so the author can assume some amount of warnings to be issued in interim versions, then a release that breaks things.  This is where "writing boilerplate is bad" bumps up into "having to edit your program on upgrade is bad."

👉 A big question:  Does this mean that the benefit to people writing new code is contingent on future changes to the defaults being much, much safer than (say) turning on strict?  Or just as valuable?

Sometimes we posit another group of people as having benefit from shifting the defaults toward modernity:

*Maintainers of perl* get benefits from the defaults shifting.  If the only way to get an old behavior is to opt in, then opting in can be made fatal.  "You have asked to enable array_base, but it was removed in v5.30.  DIE."  With that done, there's a built-in mechanism for locating code using dead features: they had to be opted in to, and the opt-in can now trigger a warning, and later an error.

I'm not sure this works.  For example, array_base was always implicitly on in the default and v5.10 - v5.14 bundles.  When it was removed, even though users thought they had been opting in (by using the bundle), the opt-in was silently removed.  We could do this because the use of the array_base feature was a detectable event.  "Sure, you were asking for this feature, before, but you weren't using it, so we can safely remove it."  Expressly asking for array_base is now fatal in v5.30, but the implicit ask for it in old bundles is not.

This implies that we can only safely kill off features that are included in version bundles only if the use of the feature can *also* be detected so that a warning can be issued.  Otherwise, we'd have to say "sorry, use v5.10 is no longer possible, because it turns on feature invisible_benefit, which has been removed and cannot be detected."  And, since the default bundle isn't even expressly requested, this gets even thornier.

*A digression on the three kinds of features:*  (and by "feature" I mean "thing governed by pragma)

1.  a feature that changes compile time behavior (like turning on try/catch blocks or "my sub")
2. a feature that changes detectable runtime behavior (like "strict refs")
3. a feature that changes "undetectable" runtime behavior (like unicode_strings) — detecting the change is possible, but fairly pointless

Of these, I think the truth is probably that it's the third category that would be the most beneficial to fix, both for new users and core maintainers.  They constitute footgun removal, but also eliminate code paths in the implementation that are there entirely to service footguns!  But you can't practically issue warnings for many of these, so it's not clear that there is a path to fixing them without a shock to the system.

*I'm getting to the end of this email.*  Sorry, I know it's been long.  I have a lot more I want to say, but:  I think the biggest question from this email (apart from the implicit "Did I make a massive error somewhere?") is the thing I flagged out with the pointy finger, above:  Having *entirely* put aside the question of the initial cost of changing defaults the first time — assuming that we make "no boilerplate" act a lot like v5.34, without incident, somehow — can we reach a state where a cycle of warning-then-change can be reliably made on a scale larger than the sorts of deprecations that we've made up until now?

I'll come back to my other thoughts on a bunch of parts of this problem in two or three days.

-- 
rjbs
Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About