http://qs1969.pair.com?node_id=479170

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

Hi all,

I'm starting to learn about Perl objects and having trouble understanding the internal workings. As I understand it, instance variables are stored in the "referenced thingy". But how does Perl do class variables? Since a 'class' is a package, is it correct to say that variables local to a package are "class variables"?

package Thing; my $class_var = 1; sub new { return bless {}, "Thing"; } sub set_class_var { $class_var = $_[0]; } 1;

I tried this out and it seems to make sense, but I hope someone can rephrase this more articulately. The other question I have concerns how class variables are stored. I want to have a single "set" method to change class variables rather than one per variable. Something along the lines of:

sub set { my $self = shift; my %args = @_; while( my ($var, $val) = each %args ) { #if $var is defined #set class_variable var to $val } }

In Python, I could use hasattr, getattr, and setattr to accomplish this. What's the Perl style to do it?

I apologize in advance if I blurted out any rubbish or missed something searching around. Any interesting beginner links to closures, Perl object internals, and symbol tables would also be cool. I'm in the process of reading the ones in the tutorial section, but still struggling through it somewhat. Thanks all in advance.

Replies are listed 'Best First'.
Re: Perl's equivalent to Python's hasattr and getattr? (class variable details)
by Ovid (Cardinal) on Jul 28, 2005 at 23:51 UTC

    Regrettably, Perl does not have a clean distinction between classes and instances of said classes. As a result, class data is something that folks tend to forget about. One way of creating your set method is to store your class data in a hash.

    my %CLASS_DATA = (...); sub set { my ($self, %args) = @_; while (my ($var, $val) = each %args) { if (exists $CLASS_DATA{$var}) { $CLASS_DATA{$var} = $val; # whoops! No validation } else { # create the var, croak, etc. } } }

    If you don't like the validation, you could have each value in %CLASS_DATA be a sub ref that points to the real setter.

    Personally, I've enjoyed Class::MethodMaker to handle much of this for me, though the recent test failures are disheartening.

    Cheers,
    Ovid

    New address of my CGI Course.

Re: Perl's equivalent to Python's hasattr and getattr? (class variable details)
by rlb3 (Deacon) on Jul 28, 2005 at 23:29 UTC
    Hello,

    I think you may want something like Class::Accessor. Class::Accessor is just one of many modules that may work for you. You may want to look at the Class:: namespace in the cpan.

      Wow, that hits it right on the spot! I find it weird that this isn't builtin. Maybe I'll skim through and look up how Class::Accessor is implemented. Is it possible to do something similar theorically by manipulating symbol tables?

        Class::Accessor is built using the symbol table. Here is the _mk_accessors as an example.

        { no strict 'refs'; sub _mk_accessors { my($self, $maker, @fields) = @_; my $class = ref $self || $self; # So we don't have to do lots of lookups inside the loop. $maker = $self->can($maker) unless ref $maker; foreach my $field (@fields) { if( $field eq 'DESTROY' ) { require Carp; &Carp::carp("Having a data accessor named DESTROY in +". "'$class' is unwise."); } my $accessor = $self->$maker($field); my $alias = "_${field}_accessor"; *{$class."\:\:$field"} = $accessor unless defined &{$class."\:\:$field"}; *{$class."\:\:$alias"} = $accessor unless defined &{$class."\:\:$alias"}; } } }