Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Self creating OO Module field accessors...

by blue_cowdawg (Monsignor)
on Jan 12, 2006 at 22:28 UTC ( #522824=perlquestion: print w/ replies, xml ) Need Help??
blue_cowdawg has asked for the wisdom of the Perl Monks concerning the following question:

OK... I confess... I'm lazy...

Given I have a module defined such that:

package BigThing; sub new { shift; my $self={ field1 => 0, field2 => "", field3 => 0x0 }; bless $self,"BigThing"; return $self; } | | Other methods | 1;
and in my module I want to provide a method such that calling:
| | hand waving here... | my $thing = new BigThing(); $thing->field1(10); printf "%s\n",$thing->field2;
but in my real module I have a lot of fields to create accessors for. Being that I'm lazy I don't want to have to write every single accessor method myself.

Did I dream this or did I see something somewhere where there was a trick or a CPAN module I could use that would invoke some sort of magic to make it appear that I wrote all those accessors and have the code behave as such by writing ONE sub that acts like them all?

Anybody know of such a thing?


Peter L. Berghold -- Unix Professional
Peter -at- Berghold -dot- Net; AOL IM redcowdawg Yahoo IM: blue_cowdawg

Comment on Self creating OO Module field accessors...
Select or Download Code
Re: Self creating OO Module field accessors...
by jdporter (Canon) on Jan 12, 2006 at 22:32 UTC

    Avoiding direct eye-contact with your question momentarily, I point out that

    package BigThing; sub new { shift; bless $self, "BigThing";
    is very bad. It makes subclassing BigThing very difficult.
    It even makes code re-use by cut-and-paste more painful than it needs to be.

    The constructor is passed the class name; it may as well use it:

    package BigThing; sub new { my $class = shift; bless $self, $class;

    We're building the house of the future together.
Re: Self creating OO Module field accessors...
by jdporter (Canon) on Jan 12, 2006 at 22:35 UTC
          You could use AUTOLOAD. (also Recipe 13.11 in the Ram.) See CategorizedQA How can I use AUTOLOAD to magically define get and set methods for my member data?

      That was it! I knew I saw it somewhere. Thanks for reminding me. My CRAFT is giving me a hard time today.

      Peter L. Berghold -- Unix Professional
      Peter -at- Berghold -dot- Net; AOL IM redcowdawg Yahoo IM: blue_cowdawg
Re: Self creating OO Module field accessors...
by Corion (Pope) on Jan 12, 2006 at 22:37 UTC

    Inheriting from Class::Accessor gives you the mk_accessors method:

    package Big::Thing; use strict; use base qw(Class::Accessor Small::Thing Needful::Things); __PACKAGE__->mk_accessors(qw(field1 field2 field3)); sub new { ... return $package->SUPER::new({ %args }); };

    Class::Accessor has the shortcoming that its constructor wants to be passed a hash reference. So you need to either override the default constructor or live with that.

Re: Self creating OO Module field accessors...
by Old_Gray_Bear (Bishop) on Jan 12, 2006 at 22:37 UTC
    Autoload (can be) your friend. I have dealt with packages where most (if not all) the accesor/mutators were generated via autoload() code. This works for 'simple' attributes reasonably well. There is a performance penalty, of course....

    ----
    I Go Back to Sleep, Now.

    OGB

Re: Self creating OO Module field accessors...
by Perl Mouse (Chaplain) on Jan 12, 2006 at 23:04 UTC
    There are a gazillion Class:: modules that will do that for you. What you also can do is:
    for my $prop (qw [field1 field2 field3]) { eval sprintf <<'END', ($prop) x 3; sub %s { my $self = shift; if (@_) {$self->{%s} = shift}; return $self->{%s}; } } END }
    Then you won't have any runtime penalty due to AUTOLOAD, or whatever runtime solution your Class:: choice uses.

    Or you could use a smart editor that allows you to create an accessor using a macro.

    Personally, if I find myself making enough accessors in a class that I start contemplating automating it, I wonder whether I really need an object, or whether I'm just creating a glorified struct. It's usually the latter - and Perl already has an excellent data structure to use as a struct: it's called a hash.

    Perl --((8:>*
          Personally, if I find myself making enough accessors in a class that I start contemplating automating it, I wonder whether I really need an object, or whether I'm just creating a glorified struct.

      I hear you! If all this module was functionally only a struct I'd certainly agree with you. Except in the case of this module there is a lot more going on.

      Peter L. Berghold -- Unix Professional
      Peter -at- Berghold -dot- Net; AOL IM redcowdawg Yahoo IM: blue_cowdawg
        You might consider whether you have an object that has-a struct that you should allow public access to. Then you'd need only one accessor method that returns a ref to the struct and allow the user to stomp all over it access its fields as required. :-)

        Caution: Contents may have been coded under pressure.

      What you also can do is:

      for my $prop (qw [field1 field2 field3]) { eval sprintf <<'END', ($prop) x 3; sub %s { my $self = shift; if (@_) {$self->{%s} = shift}; return $self->{%s}; } } END }

      I used to generate accessors in this way, in part because I felt that glob manipulation was scary and turning off strictness, however temporarily, was fragile. Tom Christiansen eventually managed to convince me that the eval approach is bad - firstly it is wasteful of memory (and processor) because each method is recompiled afresh; secondly because it is deferred, and so a perl -c check won't show problems.

      So these days I do it more like this:

      for my $method (qw/ field1 field2 field3 /) { no strict 'refs'; *$method = sub { use strict 'refs'; my $self = shift; if (@_) {$self->{$method} = shift}; return $self->{$method}; }; }

      Rather than creating 3 independent blocks of code, this creates 3 closures over the same block of code; in practice the resulting methods are otherwise identical. I also feel they are much easier to read this way, which is another aid for debugging and maintenance.

      (I saw an alternative approach to the strictness here recently:

      for my $method (qw/ ... /) { my $sub = sub { the code ... }; no strict 'refs'; *$method = $sub; }
      .. which is probably better, but I haven't started using it yet.)

      See Re: Things I Don't Use in Perl for some other things my autogenerated methods do.

      Hugo

        IMO There is a big advantage to the first style however: it actually defines the subs in such a way that you don't get weird error messages about stuff happening in an anon sub. Likewise you can set breakpoints in the debugger and stuff with the former but with the latter its not so easy. There are ways around this, but they aren't straight-forward.

        use Carp qw(confess); local *foo=sub { confess "What the fook!" }; eval qq[sub bar { confess "What the wook!" } 1 ] or die "failed to eval code: $@"; eval { foo(); 1 } or print $@; eval { bar(); 1 } or print $@; __END__ What the fook! at c:\temp\die.pl line 3 main::__ANON__() called at c:\temp\die.pl line 9 eval {...} called at c:\temp\die.pl line 8 What the wook! at (eval 1) line 1 main::bar() called at c:\temp\die.pl line 13 eval {...} called at c:\temp\die.pl line 12
        ---
        $world=~s/war/peace/g

Re: Self creating OO Module field accessors...
by pboin (Deacon) on Jan 12, 2006 at 23:58 UTC
Re: Self creating OO Module field accessors...
by santonegro (Scribe) on Jan 13, 2006 at 19:22 UTC

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://522824]
Approved by Old_Gray_Bear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others lurking in the Monastery: (7)
As of 2014-12-22 04:28 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (110 votes), past polls