in reply to Re: Re: Re: Re: OO Getters/Setters
in thread OO Getters/Setters

By your reasoning, the following code should work, and any code in the mutator to prevent it disqualifies the method as a mutator

That's correct. Accessors/mutators, by definition, provide direct access to the underlieing attributes. Since Perl is a dynamically typed language, that means doing any sort of validation on the data makes it something other than an accessor/mutator. If you're in a statically typed language, then the language does some validation for you, and it would thus still be an accessor/mutator. The important point is that you're not doing validation in your own code.

So what if it isn't an accessor/mutator? More often than not, that's a good thing. That isn't to say you have a well-designed object, but you're closer to it than if you provide direct access.

----
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^5: OO Getters/Setters
by duff (Parson) on Dec 31, 2003 at 17:01 UTC
    Accessors/mutators, by definition, provide direct access to the underlieing attributes. Since Perl is a dynamically typed language, that means doing any sort of validation on the data makes it something other than an accessor/mutator.

    Pedantry such as this seems useless to me. If the object's interface says the only way to access an attribute is by using method foo, then for all intents and purposes, foo is an accessor. Believing anything else pierces the veil of encapsulation and defeats one of the main purposes of object orientation.

    Ah, but now I'm into the fray... Quick! What's a "block structured language" and why is C not one of them? For bonus points, how does the fact that C is not block structured affect your ability to write useful applications?

      Pedantry such as this seems useless to me.

      No, I think the distinction is important. If your interface provides direct access to the attribute, it's not encapsulating anything, and thus breaking the foundations of OO design. That doesn't automatically make it bad, but it often is.

      Quick! What's a "block structured language" and why is C not one of them?

      This isn't something I've encountered before. But with a little help from Google . . .

      Block structured languages allow you to have functions nested inside other functions. C/C++ doesn't allow this, which means all those great tricks with closures in Perl and similar languages can't be done.

      ----
      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

        C/C++ doesn't allow this, which means all those great tricks with closures in Perl and similar languages can't be done.

        Pshaw. Go look in stdlib.h and figure out how qsort manages to call a function through a pointer to that function.

        That is the key element to figuring out how to do anything that you can do with closures. What C won't do for you is bind an environment around a pointer to a function, or do your memory management for you. But nothing stops you from defining a struct that contains a pointer to a function and a pointer to an environment variable, and then a function that takes said struct and an argument, then calls the anonymous function passing in both environment and argument.

        With some elbow grease you can then code by hand literally anything that you can do with closures. With the right macros you can hide most of the ugliness.

        And if you don't want to do your own memory management, then don't.

        If your interface provides direct access to the attribute, it's not encapsulating anything, and thus breaking the foundations of OO design. That doesn't automatically make it bad, but it often is.

        Hmm. I think we're in violent agreement, but our minds don't share the same map for "accessor/mutator". I think of them as "object state retriever/alterer" methods while you appear to think of them as "object attribute retriever/alterer" methods. The difference is subtle but important as an object's state is spread out over all of its attributes (and occasionally its methods too). I suppose your usage is more commensurate with the literature though.

Re: Re^5: OO Getters/Setters
by linux454 (Pilgrim) on Jan 02, 2004 at 15:56 UTC
    I'm not entirely sure where you learned object orientation, but it seems you need a new lesson in it. Object Orientation is a methodology a way of writing a program. Which means that its principles are language agnostic. Perl in my opinion is one of the worst languages to write oop programs in because it breeds hideous techniques such as yours. Attribute encapsulation is a cornerstone of OOP. The simple fact of the matter, is that accessors/mutators are methods to retrieve bits of object data or set bits of object data. What they do and how they do it is irrelevant. From my point of view, there are very few times when you would want to expose member variables (a.k.a attributes) to the public. Indeed, I've never encountered a situation which required this. I find the maintainability of encapsulation a Godsend. This allows me to trivially change the data structure without concern. You spoke of tied scalars etc, but by that argument you invalidated your previous argument over performance. You will never convince me that using a tied scalar is more efficient, easier to use, and easier to maintain than accessor/mutators. I'm sure you are a fine procedural programmer, but I would recommend you study up on your OOP before you go giving advice. May I suggest Object Oriented Perl.

    On a further note, there are times when pedantry is needed, this was not one of them. When misused pedantry is counter-productive and infuriating. It's like the force, use it well.

      From my point of view, there are very few times when you would want to expose member variables (a.k.a attributes) to the public

      But if you're blindly adding accessors/mutators, you might has well have made them public. This isn't a blanket ban on accessors/mutators, but a note that people should be more careful about adding them.

      You spoke of tied scalars etc, but by that argument you invalidated your previous argument over performance.

      Perl's objects are already slow. In any case, my tied scalar example was nothing more than an example. It demonstrates that $obj->attr and $obj->{attr} are only different in syntax, since you could use a tied scalar to preform exactly the same operations that an accessor/mutator could do. I don't recommend either approach, though, but rather eliminating accessors/mutators all together whenever possible.

      Which of these is a better object for a vending machine?

      sub money . . . # Accessor/mutator to how much money is in the machine sub get_drink . . . # Spit a drink out

      Or this, which avoids mutators entirely:

      sub insert_coin . . . # Insert a coin (quarter, dime, whatever) into m +achine sub money . . . # Accessor to how much money is in the machine sub get_drink . . . # Spit a drink out

      The second one will restrict what kind of money you can put it and adds that coin's value to the internal attribute. It is not a mutator, because it doesn't provide direct access to that attribute. money is an accesor in either case, but I don't consider it a problem, since the user needs some way of figuring out how much money is in the machine so they can insert more if need be. get_drink has the same implementation in either case, and would only spit a drink out if there was enough money in the machine.

      The second interface is more complex, but it's a better design because we've abstracted the operation of inserting coins into the machine. We can subclass it to take other kinds of coins or to take cash (though insert_coin wouldn't be the best name in that case). The point is that you've restricted what kind of data can go in, which the first class would have a much harder time doing.

      ----
      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

        But if you're blindly adding accessors/mutators, you might has well have made them public.

        Not quite sure what you mean by blindly here. As for making them public, the whole point of encapsulation is to hide implementation with an interface. Thus why should I make them public.

        This isn't a blanket ban on accessors/mutators, but a note that people should be more careful about adding them.

        More careful? How so? I would say that a/m should be used for all attributes (a.k.a. member variables) that contribute to the public interface in the least. I prefer to use the encapsulation within my objects as well, so that I can make changes internal to the object and not have to change code elsewhere. I admit sometimes this is unavoidable, or I break this pattern internally

        The second one will restrict what kind of money you can put it and adds that coin's value to the internal attribute. It is not a mutator, because it doesn't provide direct access to that attribute.

        I don't know where you came up with this idea, that a mutator may only set a member variable directly without processing, but you need to leave that definition behind. The job of a mutator is just that to mutate values. A mutator is most certainly allowed, and in fact is its job, to take input and decide what to do with it. The mutator may decide not to mutate b/c of invalid input, or it may recognize several different types of input, and be able make intelligent decisions on what to store in the object.

        For example, say we have a temperature object, internally we store the temperature in degrees celcius; However, we have a mutator (temperature [or as I prefer setTemperature, but to each his own]) that will accept temperatures in either celcius, farenheit, and perhaps other scales as well. The mutator takes the input and then does the conversion to celcius before storing the data into the object. If we took your approach then a farenheit temperature may be stored into the object, and then calculations further down the chain will get really messed up. So the solution to your method would be to create a conversion routine that you would have to pass the foreign value through and then pass the celcius temp back to the mutator. This what your telling us? You can't possibly believe that is a cleaner implementation. If you want to be pedantic, fine, but you need to realize that pedantry will only get you so far in this industry. This type of pigeon holing of the accessor/mutator definition only leads to spaghetti code, and obfuscated interfaces. I have not once encountered your definition of A/M methods.

        The excuse that "this is a case to use a mutator," is invalid, as we are talking of a methodology. Encapsulation is applicable in the simplest case just as in the most complex. I pity the programmer who truly believes that requirements will never change and writes a program with that attitude, only to find that the requirements have changed, and in the end created much more work for themselves.