Skip to content

Conversation

@demerphq
Copy link
Collaborator

@demerphq demerphq commented Mar 10, 2023

Zefram said in ZAgxPYPklHlaGfgt@fysh.org on perl5-porters mail /strictness and "use 5.whatever"/

I have an opinion on a change that was made when I wasn't around: the
deprecation and planned changes around the interaction of strictness
and "use 5.whatever" are a bad idea. The actual planned changes are
unjustified, and the deprecation doesn't match the planned changes.

First I'll consider the intended changes. As I understand it, the
intention is that in the future "use 5.whatever", for historical version
numbers, will unconditionally set the lexical stricture status, either on
or off, according to the version being requested. This is in contrast
to the present situation, where such usage can turn strictures on, for
some versions, but won't turn on strictures that have previously been
explicitly turned off. This means that, for example, "no strict; use
5.016;", which currently turns strictures off, will instead turn them
on, and "use strict; use 5.010;", which currently turns strictures on,
will instead turn them off.

What is the purpose of this change? It wouldn't remove some facility that
is onerous to maintain. The lexical stricture status will still exist.
All it would change is the arrangement of declarations by which the
strictures are controlled. The only things that could be removed as a
result are the stricture-explicitly-set bits. The cost of making this
change would be to break perfectly good existing programs that rely on,
for example, "no strict; use 5.016;" being a valid preambla that provides
a non-strict lexical status. That is not an unreasonable combination
of declarations: there's nothing a priori wrong about stricture being
declared before feature bundle. This preamble has been permitted and
had its present meaning ever since the release of Perl 5.16.

To thus change the meanings of "use 5.016;", "use 5.010;", and all the
others, is directly contrary to the promise of stability implied by the
use of an explicit version number. It's fine for "use 5.038;" to take
precedence over a prior "no strict;", if it did so consistently from its
earliest legality in Perl 5.38. But historical version numbers shouldn't
change their meanings. (The situation is different for "use 5.012;"
and "use 5.014;", which did take precedence over a prior "no strict;"
in Perls 5.12 and 5.14, but then changed meaning in Perl 5.16. That's a
historical mistake, but the 5.16 treatment should now probably stand.)

This planned change would only cause gratuitous breakage of code that
relied on the stability implied by using an explicit version number.
Doing so would not only be wrong in itself, but it would also discredit
that promise of stability, with respect to any version number, for the
indefinite future. It would become understood that to reliably set up the
lexical state requires explicitly stating the stricture and feature flags,
because the version-number bundles are unstable. This would result in
"use VERSION" becoming yet another of Perl's features that programmers
of good taste eschew but which cause a core maintenance burden forever.

Next, I'll look at the deprecation per se. The deprecated thing is
having a "use 5.010;" shadow a prior "use 5.016;" or other use with a
higher version number. As with the above, this is not actually enabling
the removal of anything problematic, but only tinkering with the way
that lexical state gets declared. As with the above, "use 5.016; use
5.010;" is not an a priori unreasonable combination of declarations:
we generally permit lexical declarations to shadow earlier ones, taking
effect in a narrower scope. And as with the above, this combination
of declarations has been legal and had its present meaning as long as
those declarations have individually been legal.

So, as with the situation regarding stricture flags, the future
fatalisation of what is now deprecated would just be gratuitous breakage.
A clean fatalisation of a particular combination of declarations is less
bad than leaving them legal and just changing their meaning, but it's
still an unjustified change that is contrary to the stability expectations
of this type of declaration. Not only would the fatalisation do damage
to the feature's reputation for stability, but some of that damage has
already been done by means of the deprecation per se.

Finally, what about the relationship between the deprecation and
the planned future change in semantics? There pretty much isn't one.
The thing that is currently deprecated and the thing that it is planned
to change (which supposedly motivates the deprecation) not only are
not the same thing, but have essentially no overlap. Things such as
"no strict; use 5.016;", the meaning of which it is intended to change,
are not deprecated, and deprecated things such as "use 5.016; use 5.010;"
pose no difficulty for the planned change in stricture control. The two
kinds of declaration combination are only quite loosely connected.

So the deprecation doesn't support the change that supposedly motivates
it, and it has no motivation of its own. It is misconceived.

In my opinion, because neither the proposed semantic change nor
the deprecation have good justification, both should be abandoned.
The deprecation warning should be eliminated, and programmers who
were affected by it should be advised to muffle the warning (which
unfortunately can't be done any more specifically than the "deprecated"
category). The documentation should stop warning about both future
changes. Doing this before 5.38 would be the way to minimise the damage
done by the bad decision in 5.36.

If there is still some compelling reason to prohibit "use 5.016; use
5.010;", then this needs to be justified in its own right. Reference to
a plan to change the treatment of stricture bits doesn't cover this issue.

If there is still some compelling reason to stop supporting the current
semantics of "no strict; use 5.016;", then it needs to be handled
differently. It should not change to just have a different effect on the
stricture bits, but rather, if the current meaning is not acceptable,
this combination should become prohibited. Any change in meaning,
whether to become prohibited or to be legal with a different meaning,
should be preceded by a deprecation cycle, where the deprecation warns
about the thing that's going to change meaning, not about an unrelated
thing located nearby.

Zefram added 4 commits March 10, 2023 15:09
Until now, "use VERSION" has only set stricture bits that were not already set explicitly. That's unlike the treatment of feature flags and warnings. This changes it so that for new versions, v5.37 and above, "use VERSION" will enable the stricture bits unconditionally, as if there had been an explicit "use strict". The meanings of "use v5.36" and below remain unchanged: they still won't override explicitly-set stricture status. "use v5.37" and above counts as explicitly enabling stricture.
Documentation was threatening that "use VERSION" for versions below 5.37 would in the future change to hard stricture setting (turning off for <5.11, on for >=5.11) that takes precedence over prior explicit stricture declarations. Now that we've determined that we're not going to make that change in the future, remove the mentions of it from the documentation. We've determined not to make that change because it would be an incompatible change that we have no need to make. The stricture setting is already hard for versions >=5.37. All that removing soft stricture setting would achieve is to free up the HINT_EXPLICIT_STRICT_* bits from $^H. With the cop_features mechanism there's no longer any pressure to free up bits there, because flags in %^H can now have performance equivalent to $^H. Even if there were pressure on $^H bits then those flags could have moved into %^H rather than disappearing altogether; because they're only touched when pragmata are processed, the performance of %^H wouldn't be an issue even without cop_features.
There isn't actually any problem with version declarations shadowing each other, including in cases where the inner declaration may disable strictures. Therefore no longer deprecate the latter.
The concept of soft stricture control has existed since Perl 5.15.6, which made version declarations perform it. Until now the concept hasn't had a name, nor a supported way to perform it on its own. This change adds adverbs to strict.pm, which support explicit manipulation of soft stricture status.
Copy link
Contributor

@leonerd leonerd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, overall a much bigger changeset than I had imagined.

I can see (and overall like) the central change around op.c's lines 7902-7906; that seems to be prettymuch what I had in mind to do, yes. I'd be happy to extract that little part out and apply it. Though I'd consider making the cut-off version 5.35, rather than 5.37, so that perl release 5.36.0 continues to have its current behaviour.

All of the rest though, I'm really unsure why it's there. In particular I don't see why any of the changes in strict.pm are needed here.

Additionally, I see that PL_prevailing_version has been removed, because it was only being used to support the version downgrade ratchet warning. We'd still verymuch like to keep that warning in place - it has overlaps with some future intended changes and other things that I'll explain in more detail in a followup email. The version number it applies to could perhaps be expanded out (in a separate change), but we'd like the overall mechanism to remain.

leonerd added a commit to leonerd/perl5 that referenced this pull request Mar 19, 2023
Original PR text by Zefram: Until now, "use VERSION" has only set stricture bits that were not already set explicitly. That's unlike the treatment of feature flags and warnings. This changes it so that for new versions, v5.37 and above, "use VERSION" will enable the stricture bits unconditionally, as if there had been an explicit "use strict". The meanings of "use v5.36" and below remain unchanged: they still won't override explicitly-set stricture status. "use v5.37" and above counts as explicitly enabling stricture. (from Perl#20923)
@leonerd
Copy link
Contributor

leonerd commented Mar 19, 2023

I've extracted just the changes in op.c (and related tests and docs) into its own PR. #20944
I've also changed the cutoff version from v5.37 o v5.36, to ensure that use v5.36 continues to behave as it does in the perl 5.36.0 release (namely, having the simplified behaviour we want going forward)

leonerd added a commit to leonerd/perl5 that referenced this pull request Mar 20, 2023
Original PR text by Zefram: Until now, "use VERSION" has only set stricture bits that were not already set explicitly. That's unlike the treatment of feature flags and warnings. This changes it so that for new versions, v5.37 and above, "use VERSION" will enable the stricture bits unconditionally, as if there had been an explicit "use strict". The meanings of "use v5.36" and below remain unchanged: they still won't override explicitly-set stricture status. "use v5.37" and above counts as explicitly enabling stricture. (from Perl#20923)
leonerd added a commit to leonerd/perl5 that referenced this pull request Aug 1, 2023
Original PR text by Zefram: Until now, "use VERSION" has only set stricture bits that were not already set explicitly. That's unlike the treatment of feature flags and warnings. This changes it so that for new versions, v5.37 and above, "use VERSION" will enable the stricture bits unconditionally, as if there had been an explicit "use strict". The meanings of "use v5.36" and below remain unchanged: they still won't override explicitly-set stricture status. "use v5.37" and above counts as explicitly enabling stricture. (from Perl#20923)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

3 participants