Friday, 10 July 2009

The strictperl experiment

The strictperl experiment by chromatic, and the strict-by-default patch by Steffen Mueller, will help me explain what approaches are right or wrong in dealing with Perl 5 evolutions.

strictperl is, as chromatic puts it, unilaterally enabling strict for all code not run through -e. Unsurprisingly, that breaks a lot of code. And I mean a lot, as in "most". Not only on the DarkPAN (I seldom use strict for scripts of four lines), on the CPAN (I have modules that will break under strictperl), but in the core itself. chromatic mentions Exporter and vars as modules that break under it. Well, of course they break. Their very purpose is to manipulate symbols by name, which is exactly the kind of thing that strict prevents. (Incidentally all code that uses Exporter or vars can't run under strict perl, and I think that's most of the Perl code out there actually.) That is why chromatic added a separate makefile target to build strictperl: if the patch was going in perl itself, perl couldn't be even built! That's how broken it is.

It's certainly interesting to dive in Perl's internals, but to experiment with enabling strict on a global level, a simple source filter would have been sufficient. One could have written one in ten minutes, including time to look up the documentation, and it would have been immediately obvious afterwards why it was a bad idea. Except to chromatic, who still thinks it's (quoting) a feature I believe is worth considering.

So now let's look at Steffen Mueller's solution, which is strictperl done right, and which is already in bleadperl.

Currently, with bleadperl, a simple use 5.11.0 will enable strictures in the current lexical scope, like use strict would do, but implicitly. (It will also enable features, but that's unrelated.) Look:

$ bleadperl -e 'use 5.11.0; print $foo'
Global symbol "$foo" requires explicit package name at -e line 1.
Execution of -e aborted due to compilation errors.

Moreover, like in chromatic's strictperl, a simple -e or -E won't enable them, because strictures are not wanted for one-liners.

That way, we don't break code that doesn't want strictures, (actually we don't break anything at all that doesn't require 5.11.0 already, it's completely backwards compatible), but it's still removing some boilerplate for default strictness if you're requesting a perl recent enough.

Steffen's patch itself is not very recent, but I didn't apply it to bleadperl immediately, because I disagreed with the implementation. As you can see in the sources, it uses Perl_load_module to load the file and execute its import() method. That's very slow. I applied it when I got around to make it faster with the next commit, which replaces that method call by just flipping three bits on an internal integer variable.

All this goodness is coming to you in Perl 5.12 when someone will be willing to take the pumpking's hat.

Next time, I'll explain why enabling warnings by default is not a good idea.


Nicholas said...

One could have written one in ten minutes

Or, even faster, download one from CPAN.

baud said...

I don't think this makes it a bad experiment though - if somehow Exporter could be made to work under this model (I'm just hand waving here!) then it'd still be an interesting experiment.

Christian said...

I'm actually surprised that there are Perl core modules that would break with strict enabled. Given how much importance is put on the use of it, the Perl community should be moving heaven and earth to get them to work with strict, something which is by no means impossible.

Rafael said...

Well, no-one ever submitted a patch to make those modules work with strict. Apparently people prefer to fix real bugs instead.

George said...

Apparently people prefer to fix real bugs instead.

It's also possible that converting them to strict-safeness will uncover heretofore unknown bugs.

It'd be a good "perltodo" item.

Rafael said...

Yes, that would be a good todo item, and more generally, make core modules a bit more in line with modern practices, like using lexicals.

However I doubt that adding strict will uncover bugs in code that old and that widely used. It could add some, though (see here for a similar story on the core module Attribute::Handlers)

So extreme care must be taken when adding strictures.

Christian said...

You might be right that there are more important things that need fixing. (Personally I wish strict = default would've been done years ago.)

However I think that lack of action on this can be attributed more to a lack of public knowledge of this, than to people actively dismissing it in favor of other things.

James Mastros (theorbtwo) said...

I think, to a large degree, you are overstating your case. First off, it's completely possible to have the code upstream of "vars" or "Exporter" be strict-compatable. To a large degree, in fact, that's the whole point of "vars".
Secondly, "fixing" them is trivial: Put a "no strict" at the top.
Thirdly, you *can* make them strict compliant without "no strict" (or equivelent but eviler tricks, like modifying $^H directly). You simply have to modify $foo::{bar} instead of ${foo::bar}. It's not that hard.