In the CB earlier today an aspirant asked how a call to an unrelated constructor could be clobbering an existing object. After the usual round of questions, answers and red herrings a little code was posted to a scratch pad. The key elements were:

my $self = bless {}, $class; ... my $self->{agent} = WWW::Mechanize->new ();

Of course presented like that the problem is immediately obvious, but the reason may not be.

So, in the style of Hofstadter's 'Gödel, Escher, Bach: an Eternal Golden Braid' I offer the following conversation (with names changed to protect ... whatever). We pick up the CB chat from the point where there was some runable code:

Zeno: Ah. Running the script with -w (resp. use warnings), it tells me that my $self->{agent} = is redefining the my $self; variable

Tortoise: warnings are your friend.

Achilles: In this case strict does the trick

Tortoise: Tortoise lost out to Zeno again, but only because he had to ssh to somewhere with www::mech installed

Tortoise: A: it does?!

Zeno: Achilles: No, that code is strict safe it seems

Tortoise: the code has strict

Achilles: I guess it's equivalent to (my $self)->{agent} = WWW::Mechanize->new ();

Achilles: Yup. It's compile time, not run time. Redeclares $self

Zeno: That code is strict-safe. Even though I wonder why my $self->{foo} doesn't raise an "Can't use undef as a reference" error

Zeno: I guess this could be construed as a bug, but I'm not sure where the bug starts. In theory, it should be a runtime bug, because as Achilles says, it should be equivalent to (my $self)->{agent}, which should be a (de)ref error.

Achilles: Interesting. In Komodo it shows as a warning in the editor so I assumed it was a stict issue

aspirant: Ahhh, I see now

aspirant: Thanks guys! That "my" should definitely not be there.

Zeno: Ah. $self then autovivifies? into a hashref. It shouldn't IMO.

Zeno: At least not while strict is enabled.

Zeno: The behaviour differs between perl -Mstrict -e "undef->{foo} = 'bar'" # fails and perl -MData::Dumper -Mstrict -e "my $self; $self->{foo} = 'bar';print Dumper $self" # doesn't fail

Achilles: Hmm, yes, it does look like a Perl bug.

Tortoise: Zeno my isn't a named unary operator; it has precedence above -> it seems

Zeno: I'm not sure if that can be explained through autovivification, because I think that the top-level thing should be a reference.

Tortoise: Zeno what? why would strict affect autoviv?

Zeno: Tortoise : I can take the my out of the equation (see above oneliners)

Achilles: Even so Tortoise $self should be undef

Zeno: Tortoise : For lack of a better term, I used "autovivification" for "turn undef into a hashref", which I think is what happens on deeper levels. It shouldn't happen at top-level, but maybe that's just consistent with what happens deeper down.

Achilles: Err, in other words - wot Zeno said

Achilles: Achilles heads off for coffee before he says anything silly(er)

Tortoise: Zeno afaict it should happen; your undef-> case fails because PL_sv_undef is readonly I think

Zeno: Tortoise : Yes. I think the behaviour of $self->{foo} = 'bar' is consistent with $self = {}; $self->{foo}->{bar} = 'baz' creating intermediate levels, but I'm not too sure whether strict should allow that at the toplevel. Whether it ...

Zeno: ... can prohibit that at the top level, I'm not sure. It would be hard I guess.

Tortoise: I think you are confusing things. autovivification at intermediate levels gets more attention because it's easier to do by accident, in a presumed "readonly" context. but it certainly happens at the outermost level too, in a modification context

Zeno: Tortoise : Ah

Zeno: I haven't witnessed it at the outermost level yet :)

Achilles: Damn pitty aspirant didn't post it as a SOPW. This is a discussion worthy of a FP'd node ;)

Zeno: Achilles: You could still make a meditation out of it :)

Achilles: Maybe one of you ought write it up as a Meditation?

and so, that's what I have done.

The bottom line is that Perl sees the second assignment as:

(my $self)->{agent} = WWW::Mechanize->new ();

which redeclares $self and sets it to undef. The ->{agent} = ... then autovivifies a hash ref to which the new $self is set. Perl never ceases to amaze!


True laziness is hard work

In reply to You can autovivify that there? by GrandFather

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.