blahblah has asked for the wisdom of the Perl Monks concerning the following question:

Please consider this code:

package Help; use strict; use warnings; sub new { my ($class, %args) = @_; my $self = {}; bless $self, $class; # populate $self->{attributes} = [qw(foo boo)]; $self->$_($args{$_}) for @{$self->{attributes}}; return $self; } sub foo { my ($self, $value) = @_; if (defined $value) { $self->{foo} = $value; return 1; } else { return $self->{foo}; # shouldn't this autoviv? } } sub boo { my ($self, $value) = @_; if (defined $value) { $self->{boo} = $value; return 1; } else { return $self->{boo}; } } package main; use Data::Dumper; # no autoviv? what? my $obj_01 = Help->new(); print Dumper($obj_01); # we set values - that works my $obj_02 = Help->new(foo => '', boo => "value"); print Dumper($obj_02); # again, no autoviv (I expect it to be the same as 01 # but am still surprised there is no autoviv happening) my $obj_03 = Help->new(foo => undef, boo => undef); print Dumper($obj_03); 1;
Ack!

Thanks

Replies are listed 'Best First'.
Re: Why is this not autovivifying?
by Fletch (Bishop) on Apr 02, 2007 at 15:33 UTC

    Autovivification happens in an lvalue context, but you're using it only as an rvalue in the else branch of your accessors.

    Update: And just to be (more :) pedantic, this isn't strictly speaking autovivification that you're expecting (that's automatically creating a reference to the proper data type when undef is used in an lvalue context). What you're seeing is access to a non-existent hash slot not creating an entry in that slot.

      Ah. Thank you very much Fletch for the excellent and succinct explanation. I'm really disappointed I didn't know that before - and judging from the -1 vote I'm not the only one disappointed that I didn't know that before.

      Thanks!

      Not at all. An lvalue context is not required.

      print $hash{foo}{bar}; # Autovivifies $hash{foo}

        Oop, quite right. The presence of 'lvalue' in perlref was still in my mind. It's more like 'the use of an undef value (retrieved from somewhere which could be an lvalue; i.e. $a->{"foo"} will, undef->{"foo"} won't) to the left of a -> (implicit or explicit) attempting to dereference the value'.

Re: Why is this not autovivifying?
by saintly (Scribe) on Apr 02, 2007 at 16:05 UTC
    Perl autovivifies (http://en.wikipedia.org/wiki/Autovivification) only when it has to, and when it has some idea of what value you want to implicitly create.
    In your example, Perl can't create the '$self->{boo}' value implicitly because it has no idea what it should be. It would be inappropriate if it created it with 'undef', '""' or '0'.
    $thingy{'someElement'}++; # vivifies it to '0' before you increment it to '1' $thingy{'someElement'} .= "Foo!"; # vivifies it to the empty string... $thingy{'someElement'}{'otherElement'} = "Foo!"; # vivifies someElement to a hash reference
    In your case, you would want Perl to create the element 'foo' so that it would exist in the structure of the object, but that would be detrimental in many cases, and make it difficult to check the structure of objects if every element was created when you looked at it.