Advocates of strict typing systems often tell the reliability bedtime story when explaining why looser type systems give them the howling fantods. They're not entirely wrong, either.
Quick, what's the problem with this Perl code?
no strict 'refs';
*{ $classname . '::' . $subname } = sub { ... };
Don't worry if you don't get it immediately. It's subtle: within the body of the anonymous sub, you have to enable strict reference checking or Perl will silently ignore any symbolic references.
Maybe that's not a problem for the person who first wrote that code. He or she knew exactly what to write and made no typos. Great! I wish I were that careful and fortunate.
I can think of very few reliable, maintained Perl 5 programs which don't have strict
enabled in the broadest scope. Our community practices and our tooling and our default idioms (whether enabled by language or convention) shape the way we think and behave.
Now imagine what might happen six months later when someone else (or the original developer) needs to make a change to that code. Would you remember that strict 'refs'
is off in that code? (I believe I owe credit to Joshua ben Jore for first mentioning this problem; it's an example of a poorly recognized problem from the Tower of Defaults.)
The solution in this case is to ensure that loosening strictures occurs in the smallest sufficient possible scope. A similar principle exists for both physical and virtual security. A better version of that code might be:
my $subref = sub { ... };
{
no strict 'refs';
*{ $classname . '::' . $subname } = $subref;
}
Not only does the tight scoping limit the effects of disabling strict references, it gives visual cues to maintainers that something different is happening. Proceed with mindfulness. This is even a user interface principle: make exceptions obvious.
Rafael believes that strictperl is a broken idea, so immediately obviously bad that it's suitable only for a source filter. One of his gripes is that it does not run the vars pragma nor Exporter unmodified.
He's right. It unrepentently does not.
Rafael says that the "very purpose [of vars
and Exporter
] is to manipulate symbols by name, which is exactly the kind of thing that strict
prevents." He's right about that too.
Follow those links, though. Look at the implementations of Exporter
and vars
. Count the lines of each that absolutely cannot run with all strictures enabled. Count the remaining lines.
Done? Great. Now tell me with a straight face that foundational core libraries that have been in Perl 5 for fifteen years are paranoid enough.
These modules do not have to break under strictperl
. They could run unchanged (as far as everything else which uses them notices). There are no backwards-incompatible changes by modifying them to disable strictures in the smallest necessary scopes.
If strict
is useful enough that you use it in all programs you expect to maintain, if you believe it protects you against problems you didn't expect, even if you have a copious test suite, tell me that it's not worth even asking if it's useful for the more than 90% of code in vars
and Exporter
(just as examples) that does not need to disable strictures.
You may believe that this is a silly, dumb, useless experiment I've wasted my time writing C and portable Make rules when I could have written a frivolous little source filter. You may be right. Feel free to ignore it, mock it, file bug reports about it, whatever you like.
Yet I believe this stupid little experiment may be useful -- not just for people who want to practice exception-based strictures (strict by default: exceptions as necessary) but also for people who would like to make future problems even less likely to occur, especially in Perl 5's core library itself. (Isn't that one great way to measure maintainability?)
Limiting the scope of loosened strictures is by no means the only way to improve the reliability and maintainability of serious programs, but why not take advantage of the possibility to do so?
I fully agree with you here that cleaning the old libraries is not a idea. But on the other hand the 'use 5.11.0' solution by Steffen Mueller and advertised by Rafael does seem like a compromise, it cuts enough boilerplate to be quite useful.
I prefer to write it the other way around:
@zbigniew,
I agree. I'm glad to see the use 5.11.0; enhancement; it's definitely an improvement.
We actively ran into the strict problem at work. We were making methods for object attributes but occasionally someone would forget and call them as a class method. Because of this behavior and non-obviousness, it all "just worked."
In those cases, the code would turn out to be assigning to the global variable
instead of the attribute of the object.W.
T.
F.