in reply to Modules for autogenerating accessor/mutator methods

There were a couple of blogs with titles like "getters/setters considered harmful for python/php". The authors were proposing to access the member variables directly, unless one wants to add some logic like validation. That, of couse, breaks encapsulation. Any comments?
  • Comment on Re: Modules for autogenerating accessor/mutator methods

Replies are listed 'Best First'.
Re^2: Modules for autogenerating accessor/mutator methods
by magog (Beadle) on Jun 05, 2005 at 19:28 UTC

    The blogger agrees that you should make your object's data available to the outside world in a way lets you change the underlying implemtation when you need to.

    In Java, it seems like the "best practice" is to copy and paste a bunch of identical get/set methods.

    The blogger seems to be against copying and pasting when native language features can give you the same benefit. With Python (apparently) you can use the built-in features to make public attributes that can be transparently upgraded from simple attributes to get/set methods, without changing the API:

    contact.email = "x@x.com"

    Behind the scenes this can be implemented by a simple attribute variable or a get/set method. The user of the object doesn't care.

    This feature isn't built in to Perl 5. If you break encapsulation and access the underlying hash keys directly:

    $contact->{'email'} = "x@x.com";

    Then you can't protect the access without a tied hash. On the other hand, if you wrap the accessor in a method:

    $contact->email("x@x.com");

    Then you have to copy and paste multiple identical get/set methods.

    The better solution is to let a module generate the methods for you. For instance, Attribute::Property (which looks excellent, BTW - thanks for pointing it out, wolv!), automatically makes methods that are assignable like hash elements:

    # module code sub email : Property; # ... # user code $contact->email = "x@x.com";

    When you need to upgrade 'email' to do some validation, you can change the accessor into a full sub:

    # module code sub email { # do some validation or processing here } # ... # user code - API stays the same. $contact->email = "x@x.com";

    Michael

      Mind you, Attribute::Property generates lvalue subroutines, so a simple 'sub email { }' won't replace the interface in a compatible way. Furthermore, A::P supports adding validation and processing: sub email : Property { process; validate } The return value of the block will indicate whether the value given validates.

        Hmmm... That's a good point. It's the same thing with Class::Accessor::Lvalue. When you want to upgrade to a full method, you're stuck: there doesn't seem to be an easy way to make an lvalue subroutine that has access to the rvalue.

        Update: But you're right - Attribute::Property does allow you to do all the processing you want, as long as you follow it's rules. So it's probably enough.

        Update: For instance, you could do:

        sub email : Property { my $self = shift; $_ = 'some_arbitrary@address.com'; 1; } # ... # user code $self->email = 'my@address.com'; print $self->email; # prints some_arbitrary@address.com

        Michael