I've been reading Conway's OO Perl. He offers pseudo-hashes as a solution to the problem of autovivification of object entries that don't exist. Now pseudo-hashes don't enjoy the best reputation and they'll be gone come Perl 6. As an alternate solution I came up with this simple bit of code which I placed in the constructor of Conway's 3.4 code listing beginning on page 114:
if (%arg) { #performed only if obj. + arguments given my %_temp_hash = _return_attr_data(); #returns list + of obj. attributes foreach my $argcheck (keys %arg) { next if exists $_temp_hash{"_" . $argcheck}; #checks if + attribute exists croak "An invalid CD attribute given"; #if not, cro +aks with error } }
So what's wrong with this as a solution to prevent the autovivification of an object attribute? Is there a reason why something like this isn't offerred as a solution in Conway's book? To view the above code in its complete context with my additions in bold...
package Music; $VERSION = 1.00; use strict; use vars qw( $AUTOLOAD ); use Carp; { # Encapsulated class data my %_attr_data = # DEFAULT ACCESSIBILITY ( _name => [ '???', 'read'], _artist => [ '???', 'read'], _publisher => [ '???', 'read'], _ISBN => [ '???', 'read'], _tracks => [ '???', 'read'], _rating => [ -1, 'read/write'], _room => [ 'uncatalogued', 'read/write'], _shelf => [ "", 'read/write'], ); my $_count = 0; # Class methods, to operate on encapsulated class data # Is a specified object attribute accessible in a given mode sub _accessible { my ($self, $attr, $mode) = @_; $_attr_data{$attr}[1] =~ /$mode/ } # Classwide default value for a specified object attribute sub _default_for { my ($self, $attr) = @_; $_attr_data{$attr}[0]; } # List of names of all specified object attributes sub _standard_keys { keys %_attr_data; }
sub _return_attr_data { %_attr_data; }
# Retrieve object count sub get_count { $_count; } # Private count increment/decrement methods sub _incr_count { ++$_count } sub _decr_count { --$_count } } # Constructor may be called as a class method # (in which case it uses the calss's default values), # or an object method # (in which case it gets defaults from the existing object) sub new { my ($caller, %arg) = @_; my $caller_is_obj = ref($caller); my $class = $caller_is_obj || $caller; my $self = bless {}, $class;
if (%arg) { my %_temp_hash = _return_attr_data(); foreach my $argcheck (keys %arg) { next if exists $_temp_hash{"_" . $argcheck}; croak "An invalid CD attribute given"; } }
foreach my $attrname ( $self->_standard_keys() ) { my ($argname) = ($attrname =~ /^_(.*)/); if (exists $arg{$argname}) { $self->{$attrname} = $arg{$argname} } elsif ($caller_is_obj) { $self->{$attrname} = $caller->{$attrname} } else { $self->{$attrname} = $self->_default_for($attrname) } } $self->_incr_count(); return $self; } # Destructor adjusts class count sub DESTROY { $_[0]->_decr_count(); } # get or set room&shelf together sub get_location { ($_[0]->get_room(), $_[0]->get_shelf()) } sub set_location { my ($self, $room, $shelf) = @_; $self->set_room($room) if $room; $self->set_shelf($shelf) if $shelf; return; } # Implement other get_... and set_... methods (create as necessary) sub AUTOLOAD { no strict "refs"; my ($self, $newval) = @_; # Was it a get_... method? if ($AUTOLOAD =~ /.*::get(_\w+)/ && $self->_accessible($1, 'read') +) { my $attr_name = $1; *{$AUTOLOAD} = sub { return $_[0]->{$attr_name} }; return $self->{$attr_name}; } # Was it a set_... method? if ($AUTOLOAD =~ /.*::set(_\w+)/ && $self->_accessible($1, 'write' +)) { my $attr_name = $1; *{$AUTOLOAD} = sub { $_[0]->{$attr_name} = $_[1]; return }; $self->{$1} = $newval; return; } # Must have been a mistake then... croak "No such method: $AUTOLOAD"; } 1; # Ensure that the module can be succesfully use'd

$PM = "Perl Monk's";
$MCF = "Most Clueless Friar Abbot Bishop";
$nysus = $PM . $MCF;
Click here if you love Perl Monks

Edit: chipmunk 2001-007-15


In reply to Preventing autovivification of object attributes by nysus

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.