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!
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: You can autovivify that there?
by Anonymous Monk on Feb 23, 2009 at 10:23 UTC | |
|
Re: You can autovivify that there?
by Bloodnok (Vicar) on Feb 23, 2009 at 11:52 UTC | |
|
Re: You can autovivify that there?
by ikegami (Patriarch) on Feb 23, 2009 at 15:38 UTC | |
by codeacrobat (Chaplain) on Feb 27, 2009 at 18:48 UTC | |
|
Re: You can autovivify that there?
by zentara (Cardinal) on Feb 23, 2009 at 11:33 UTC | |
by Anonymous Monk on Feb 23, 2009 at 11:47 UTC |