Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

Class::Accessor and Damian's PBP

by cbrandtbuffalo (Deacon)
on Feb 22, 2006 at 16:09 UTC ( [id://531997]=perlquestion: print w/replies, xml ) Need Help??

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

Class::Accessor is a very cool module and eliminates some of the drudgery of Perl OO programming. It auto-creates accessors in the common Perl way, that is, it sets if you pass it something and gets if you don't.

In Damian's Perl Best Practices, he recommends separate get and set methods with the prefix set_ and get_ to make it explicit what you intend to do.

Now, part of why he recommends this is to avoid the omission of errors when you try to set something that you don't want set. Class::Accessor takes care of this with read-only methods, so at least you would get an error.

To make the module follow Damian's suggestion, would it be a matter of making it generate get_ and set_ methods? Has someone already addressed this somewhere and I'm missing it?

I believe Class::Std handles this for inside-out objects, but I'm looking for a way to follow the suggested practice for old-fashioned perl objects (without writing all those accessors myself).

Thanks.

Replies are listed 'Best First'.
Re: Class::Accessor and Damian's PBP
by Roy Johnson (Monsignor) on Feb 22, 2006 at 19:40 UTC
    If you have so many accessible properties that you need to generate accessors for them, you may need to re-think your design. Accessors are a code smell.

    But assuming you have good reason to have so many accessors, I'm sorry to say I don't have a satisfactory answer to your question. I would go with Class::Accessor::Lvalue because I think that something that behaves like a variable (being settable and gettable) should have an interface like a variable. It is also very clear about when you're setting and when you're getting. If you then use Class::Accessor for the read-only accessors, everything is taken care of.


    Caution: Contents may have been coded under pressure.
      If you have so many accessible properties that you need to generate accessors for them, you may need to re-think your design. Accessors are a code smell.

      I'm not sure that I entirely agree with that assertion.

      Most OO classes will have a number of properties, but unfortunately Perl's object model does not provide a standard way to define those properties. The simple and common approach is to store properties as keys in a hash but this leads to hard-to-find bugs resulting from typos in hash keys. Generating accessors is an effective way to eliminate that class of error.

      I do agree that lots of accessors in the public API of a class is often a problem with the design.

      The examples on the page you linked to seem to be written in a language that, unlike Perl, supports both properties and private methods.

        The simple and common approach is to store properties as keys in a hash but this leads to hard-to-find bugs resulting from typos in hash keys. Generating accessors is an effective way to eliminate that class of error.
        Have you already tried to use fields;?
        Not that I dislike accessors, but I think this is not the exact reason why they're good.


        acid06
        perl -e "print pack('h*', 16369646), scalar reverse $="
        The reason accessors are a code smell is that OO programming is supposed to be about objects performing tasks that they know how to do, not programmers fiddling with the objects' internal states. The internal states should primarily change as a result of interacting with their universe. If that's not the case, then maybe OO is the wrong approach.

        That is not to say that there should be no public accessors in good OO code. Code smell is not an absolute condemnation, it's just a marker that should make you think twice.


        Caution: Contents may have been coded under pressure.
      Whenever your setter needs to be normalized to a different value lvalue accessors don't cut it.
      -nuffin
      zz zZ Z Z #!perl
        Whenever your setter needs to be normalized to a different value lvalue accessors don't cut it.
        Well...that certainly used to be the case. Indeed, the fact that you have to employ the complexities of tied proxy variables to retain control when using lvalue accessors, is precisely why I cautioned against lvalue accessors in "Perl Best Practices".

        But last week I released the latest version of the Contextual::Return module, with which you can now hide all the complexity of tied proxies behind two simple LVALUE, and RVALUE blocks. For example:

        use Contextual::Return; # Name method offers unconstrained access... sub name : lvalue { my ($self) = @_; $name_of{ident $self}; } # Rank method constrains access: can assign only valid ranks # (value being assigned is passed as $_ to LVALUE block)... sub rank : lvalue { my ($self) = @_; LVALUE { croak "Invalid rank ($_) assigned" if !$is_valid_rank{$_}; $rank_of{ident $self} = $_; } RVALUE { $rank_of{ident $self}; } } # Serial method offers read-only access... sub serial { my ($self) = @_; return $snum_of{ident $self}; }

        With this functionality now available, I'm seriously reconsidering my long-held objections to lvalue accessors.

        Damian

        Neither do generated accessors. So you have to write something. For either kind of accessor, tie is one way to do it.

        Caution: Contents may have been coded under pressure.
      If you have so many accessible properties that you need to generate accessors for them, you may need to re-think your design.

      I'm working on a configuration module, so accessors and data are the primary purpose of the module. You can see some background in Configuration Best Practices for Web Apps.

      Even if you don't have many, though, I would argue the good kind of Laziness should drive you to use tools to avoid cut and paste. Even with just a few accessors, the code often ends up being largely cut and pasted, so using a module to automate the process is still a nice idea.

        After playing around in several directions, I realized that it's trivially easy to generate default accessors, which may be why there are so many modules for it (although it makes me wonder why there are any).
        for my $property (qw(several members defined public)) { no strict 'refs'; *{"get_$property"} = sub { (shift)->{$property} }; *{"set_$property"} = sub { (shift)->{$property} = $_[0] }; }

        Caution: Contents may have been coded under pressure.

      Lvalue properties are fine if you're using Visual Basic or another language where they're better supported. They're a bad idea in perl.

      ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

        Could you elaborate more on this subject (or point me to other nodes regarding this discussion)?
        Are there any specific issues regarding Lvalue accessors so that everyone seems to dislike them?


        acid06
        perl -e "print pack('h*', 16369646), scalar reverse $="
Re: Class::Accessor and Damian's PBP
by nothingmuch (Priest) on Feb 22, 2006 at 21:06 UTC
    Class::DBI has some kind of prefixing support interacting with Class::Accessor. Look at the code and steal it =)

    -nuffin
    zz zZ Z Z #!perl
      Thanks for the pointer.

      It appears CDBI is using Class::Accessor in the currently support method of overriding get and set. After looking at Class::Accessor, I think what I want is a way to provide my own alias that is different from the actual field name, which isn't supported right now.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://531997]
Approved by matija
Front-paged by Arunbear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (6)
As of 2024-03-19 02:35 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found