views:

87

answers:

2

I'm wondering, does -MO=Deparse show you all of the Perl optimizations, and why doesn't this get folded in Perl 5.10?

$ perl -MO=Deparse -e'[qw/foo bar baz/]->[0]'
['foo', 'bar', 'baz']->[0];
-e syntax OK

Some on IRC thought that O=Deparse might not be showing it all, but it certainly shows some constant folding.

$ perl -MO=Deparse -e'use constant "foo" => "bar"; foo'
use constant ('foo', 'bar');
'???';
-e syntax OK

Same result if I explicitly write the constant sub. While predictable, it is also rather interesting that the documentation in constant.pm has you create a constant list rather than a constant array. I assume that not just is this not folded like scalar constants but it requires the overhead of creating a new array on every invocation.

$ perl -MO=Deparse -e'use constant foo => qw/foo bar baz/; (foo)[0]'
use constant ('foo', ('foo', 'bar', 'baz'));
(foo)[0];
-e syntax OK

The only conclusion that I can come to is -MO=Deparse is showing all of the folding, and constant arrays are just not optimized out in Perl? Is this so? Is there a technical reason for it?

+4  A: 

You can't create constant arrays because arrays are not data. Perl 5 has five types of data (things that can be stored in variables):

  • no value (undef)
  • numbers
  • strings
  • references
  • lists (made up of one or more of the previous types)

You can make a constant out of any of those. Perl 5 also has three containers:

  • Scalar
  • Array
  • Hash

Scalars can hold any of the first four types of data, arrays and hashes can hold lists. It is important not to confuse things that hold data and the data itself.

As for B::Deparse, it dumps the optree after it is built, so it will show the results of all constant folding.

I haven't thought about it enough yet, but I do not see any obvious reasons that it couldn't be folded.

Chas. Owens
Could you explain `-MO=Deparse -e'use strict; print {}->[1]` vs `use strict; print {}->[1]`. At some point, strict knows you're trying to get at an invalid reference for an Nth element (ie. that `{}` is a hash ref). I know we say proverbially that the state strict operates in is compile-time. How does strict know what type of reference this is? Could you possibly explain a little more down that direction?
Evan Carroll
@Evan Carroll The strict pragma doesn't catch that, it only cares about declaration of variables (`"vars"`), banning symbolic references (`"refs"`), and banning most bareword strings (`"subs"`). The `->` operator dereferences at runtime, which is why we don't get an error until then. If we made `->` do constant folding we could probably catch that specific error at compile time.
Chas. Owens
The rule of thumb has always been that `strict` doesn't slow down runtime. Things that did that were reserved for `warnings.pm`. So strict is making a pass over the op-tree at runtime during BEGIN{} and throwing the exception, or strict is asserting the reftype is valid at a speed cost during runtime? -- Or, am I still not getting it.
Evan Carroll
The `strict` pragma can't slow down runtime (unless your runtime contains a new compile time through string `eval`). All of its affects are at compile time. I believe `strict` runs as the optree is built, not afterward. You are also still not getting it about `strict`. This is a Perl 5 runtime error and has nothing to do with `strict` or `warnings`. It is analogous to `perl -e '$x=$y=0; $x/$y'`.
Chas. Owens
you're totally right, ekk `perl -e'die; print {}->[1]'` it is a runtime assertion that catches this.
Evan Carroll
I would like to note, I'm not yet ready to accept this answer because it seems from [your update](http://stackoverflow.com/posts/3561323/revisions) that you might be convinced it could be folded, but still isn't. I'd like to know yet why it can be in your opinion, and what reasons might prevent it from being.
Evan Carroll
@Evan Carroll I have thought about it for a while now and can see no reason it couldn't be folded. I assume the reason it hasn't been optimized yet is that it is rare to have code like `[qw/a b c/]->[0]`, but common to have code like `24 * 60 * 60`.
Chas. Owens
+3  A: 

You can't make a constant array in Perl, there's nothing in the internals to indicate a constant array or hash or even a scalar. "use constant" takes advantage of Perl's ability to inline subroutines with a prototype of () and simple code. The best you can do is set the readonly flag, but that can be switched off at runtime.

Perl could use the readonly flag at compile time as a hint to indicate that the array really is readonly and then inline any access using a constant index. Such a heuristic would probably be safe as the readonly flag isn't supposed to be user-accessible and you probably shouldn't be flipping it off.

Schwern
..and if you do, you deserve what you get :)
Ether