in reply to OO Getters/Setters

So, the solution to this is accessing data or setting it via methods . . . I've seen a getter/setter in OO tutorials, one written for each attribute.

Yes, most tutorials do it that way. They're wrong, or at least misleading. Getter/setter methods (or for those who like fancier words, accessors/mutators) should be avoided. Sometimes you do need them on a few attributes, but if your design calls for accessors/mutators on every internal attribute, you need to rethink your design. Doing it that way won't really result in an object, but a datastructure that happens to be accessed with an object-like syntax. The only difference between this:

$obj->{field};

And this:

$obj->field();

Is some fancy syntax. I bet the second form is slower, too (haven't benchmarked it, though).

Now when you actually do need accessors/mutators . . .

Why do you need a different method for each bit of data?

True to TIMTOWTDI, Perl offers many ways of producing accessors/mutators. Your way isn't necessarily wrong. If use strict 'subs'; was useful for method lookups, then I think you can make a stronger argument against what you're doing (since a method-per-attribute way would give you compile-time errors when you make a typo). Since methods are all looked up at run time, use strict 'subs'; isn't particularly useful no matter how you do it.

One problem with your way of generating accessors/mutators is that, unless you do checking inside the method, a user can insert an attribute that didn't previously exist.

There are other ways of generating accessors/mutators. One is to use AUTOLOAD, but it's slow. Class::Accessors works by using closures, like this:

my @FIELDS = qw( a b c d ); # Put your field names here foreach my $field (@FIELDS) { no strict 'refs'; *$field = sub { my $self = shift; $self->{$field} = shift if @_; return $self->{$field}; }; }

The symbol table will make a reference to the same subroutine each time, thus saving memory. It's also as fast as any other method lookup. If you wrap the above in a BEGIN block, there will be no runtime hit for generating the methods.

----
I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
-- Schemer

: () { :|:& };:

Note: All code is untested, unless otherwise stated

Replies are listed 'Best First'.
Re: Re: OO Getters/Setters
by dreadpiratepeter (Priest) on Dec 31, 2003 at 15:04 UTC
    I really have to disagree with your first supposition. There is a world of difference between $obj->{field} and $obj->field(). In fact, the difference is one of the cornerstones of oo.
    With the direct access, I have no control over the field. The consumer can store anything it it, squirrel away references to it, change the internal state of my object from a distance using those references, etc.
    With the accessor, I have complete control over the field. I can validate changes to the field using any criteria I choose. I can change storage methods. I can manipulate the data internally. I can do anything I need to, without breaking the users code and without the user breaking my code.

    UPDATE: It also removes an entire level of error prevention. There is no way to detect mistyped fieldnames. The following code fails silently bacause it is syntactically correct, and without accessors there is no mechanism to detect bad field names.
    my $var = $obj->{field}; $var = someManipulation($var); $obj->{feild}=$var;


    -pete
    "Worry is like a rocking chair. It gives you something to do, but it doesn't get you anywhere."

      With the direct access, I have no control over the field.

      In Perl you do, via tied scalars in the internal attributes. I don't think this method is common, but it can be done.

      With the accessor, I have complete control over the field.

      If you're doing something more complex than setting or getting an attribute (no validation, etc.), then it's not a true accessor or mutator.

      ----
      I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
      -- Schemer

      : () { :|:& };:

      Note: All code is untested, unless otherwise stated

        If you're doing something more complex than setting or getting an attribute (no validation, etc.), then it's not a true accessor or mutator
        Since when? I have always understood an accessor to be a method that presents an attribute of the the object to the consumer and a mutator to be a method that allows the user to change an attribute of an object in a controlled way. By your reasoning, the following code should work, and any code in the mutator to prevent it disqualifies the method as a mutator:
        my $year = $obj->birthyear(); $year = "Elmer J. Fudd Millionaire"; $obj->birthyear($year);


        -pete
        "Worry is like a rocking chair. It gives you something to do, but it doesn't get you anywhere."
      While this is true (and valid), there is something to be said about one of the worst abuses of OO, particularly among Java programmers....writing a getter/setter for every method to avoid making variables public. This is misguided.
      private int foo; public int getFoo() { return foo; } public void setFoo(int foo) { this.foo=foo; }

      In this case, the programmer thought that they were preventing access to an internal variable that should have been encapsulated, but they wrote methods that completely bypass that encapsulation. In this case (with no logic restricting input values), they have essentially made the "int foo" public, which is what they were avoiding in the first case. Also, this introduces greater overhead in calling additional functions.

      I would much rather see OO folks think in terms of objects and have their methods have meanings, rather than to see them implement code as merely data structures with optional bounds checking behavior.

      Essentally (and I am speaking in that accursed Java language):

      Here the methods have meaning to the object thing.move(+1,-1); Here we just have a "objectified" data structure and we aren't really OO thing.setX(thing.getX()+1,thing.getY()-1)

      So if you want to be all "Object Oriented", that's fine, but most most programs that declare them to be OO simply are not, they are just restricted data structures that are often 5x more complicated than they need to be. "Functions operating on Data" worked fine for many years and there is nothing wrong with it. For many programs, it's healthy to have a few objects mingling with non-OO constructs, since pure OO can really be detrimental in many cases. It can steamroll out of control (especially if you write a function for most variables!)

      In fact, developing good data structures and programs are really a lost art, as many OO zealots can develop huge OO tree hierachies that obfuscate a lack of good up-front design. Sooner or later, a simple program that could have been written in a 1000 lines is now written in 1000 files!