in reply to Re^8: Perl OO and accessors
in thread Perl OO and accessors

lots of needless complexity for little or no real gain.

First off, this is only needlessly difficult in Perl. Python, Ruby and many others support this kind of smart attribute out of the box.

As for the gain, it's in programmer time, readability, simplicity, conciseness and uniformity.

An attribute is essentially a variable with possibly some runtime enforced restrictions so it should be accessible just like any other variable. I can do

$radius *= 2; $h{radius} *= 2; $radii[5] *= 2;
so why should I have to do
$c->setRadius($c->getRadius * 2);
why not
$c->Radius *= 2;
?

The existence of something that fundamentally is a variable but that must be accessed in an unnatural way is actually a source of extra complexity. Accessors and mutators are something that are only necessary when the language designer didn't bother include smart attributes.

A variable hidden behind methods causes more code to be written by anyone trying to use that variable and it actually prevents code reuse. For example any function which takes a reference to a variable and alters it can not be resued if the interface for the variable is via an accessor method. Whereas an lvalue attribute will work just fine anywhere a normal variable would have worked.

Occam's razor says we should reduce the number of concepts we have to deal with, lvalue accessors mean we can throw away the awkward not-quite-a-variable attributes. Lispers realised this long ago and introduced generalised variables which give a uniform interface to "cars and cdrs of lists, elements of arrays, properties of symbols, and many other locations are also places where Lisp values are stored".

Why would I want to leave bits of a redundant API around with the caveat that, if performance is an issue, they shouldn't be used?

I think this is backwards. The Area method is the primary and recommended interface. setArea and getArea are the redundant parts of the interface (although they are an essential part of the implementation) and are available in case performance is an issue (they might also be useful if other code is expecting a setter method rather than an lvalue).

So essentially, while the implementation may be complex, it is once-off complexity, hidden even from the author of the class and results in an overall reduction of complexity and increase in productivity. If it leads to unacceptable performance issues you can choose to use to the use the more complex interface in performance sensitive places in which case you still better off than when you were using set/get everywhere.

Replies are listed 'Best First'.
Re^10: Perl OO and accessors
by sauoq (Abbot) on Nov 29, 2005 at 22:13 UTC
    First off, this is only needlessly difficult in Perl. Python, Ruby and many others support this kind of smart attribute out of the box.

    Well, since this isn't Python or Ruby, we can safely ignore them I think. As for it being "needlessly difficult", well, in my opinion it's just plain needless. When in Rome, do as the Romans. When coding Perl, do it with a method call.

    I dispute the notion that doing so would lose programmer time, readability, or simplicity. I don't believe conciseness is a goal in and of itself, but if it is, Perl excels at it in other areas, so you've still got an overall win (by far.) And, as with most things in Perl, uniformity is simply up to the programmer. He must do things in a uniform manner because the language doesn't enforce it.

    -sauoq
    "My two cents aren't worth a dime.";
    
      Well, since this isn't Python or Ruby, we can safely ignore them I think.

      *blink blink* Huh?!? When is disregarding another language's strengths a good thing? Or, is the idea "We can't do it, so it can't be good"? FYI - the Perl6 object system is heavily influenced by Ruby, Python, Smalltalk, and Lisp. In fact, as stvn has put it, the P6 OO system is meant to take the best elements from the best-of-breed languages and meld them into something that doesn't suck.

      Yes, Perl is an amazing language. By far, it's the best all-purpose language out there, with the CPAN being a major component of that. This doesn't mean that it can't be improved. If it's to be improved, one needs to find languages that do things better, then borg those features into Perl. That's what Perl has always done from the very beginning. And, that's what Perl6 is doing. Not just OO, but macros and grammars and function signatures and a lot of other things that have been seriously missed in Perl5.

      Now, you may be thinking "I do perfectly fine without X in Perl." And, yes, you're right - you do perfectly fine. But, have you ever dipped into another language that didn't have hashes or regexes or lists that DWIM? In other words, have you ever written in C, Java, or Javascript*? After working in Ruby for about a month, it's like pulling teeth to work in Perl5's OO. It feels clunky, wordy, and just plain too complicated. It literally feels like I'm back in ANSI C or Pascal. Heck, coming back to Perl5 from Ruby feels that way in nearly every sense. As a few people have put it on the Perl6 langauge list, Ruby is the closest we're getting to Perl6 until Perl6 is out.

      *: Before you say that JS has hashes, it doesn't if someone changes Object.prototype anywhere at anytime, like the oft-used prototype.js library does.


      My criteria for good software:
      1. Does it work?
      2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
        When is disregarding another language's strengths a good thing?

        Gee... just about anytime you aren't discussing language design or making comparisons. Which, in case you hadn't noticed, we weren't. We were talking about good ways to do things in Perl . (And, by "Perl", I mean the one people use for serious work now; not 6.)

        Now, you may be thinking "I do perfectly fine without X in Perl.

        You seemed to have missed the mark here. There are plenty of things from other languages that I miss in Perl. But I don't try to jerry-rig them in Perl just because they aren't there. I take the pragmatic approach, the path of least resistance, and do it the way that makes sense in the language I'm working with. (And that's a fair summary of the node to which you were replying.)

        In other words, have you ever written in C, Java, or Javascript?

        For the record, sure. All three. Far more in C than Java or (snort) JS. C++ too. And quite a bit of Python at one time. And some TCL. And Lisp. CLIPS. Fortran. Pascal. Basic. Various shells, of course. A tiny bit of Ada once (which, thankfully I've forgotten everything about except its god-forsaken verbosity.) And, more recently, yes: Ruby; which is, I agree, very nice indeed. (Nice enough, in fact, that by the time Perl6 come into its own, I'll probably have to be converted from Ruby.) But still, I won't be getting entirely away from Perl5 anytime soon.

        -sauoq
        "My two cents aren't worth a dime.";
        
Re^10: Perl OO and accessors
by herveus (Prior) on Nov 29, 2005 at 22:33 UTC
    Howdy!

    An attribute is essentially a variable with possibly some runtime enforced restrictions so it should be accessible just like any other variable.

    That is needlessly restrictive, and the conclusion does not follow from the premise. Suppose you have a timer that is counting up/down. You may have, as an "attribute", the elapsed time/time remaining. Should that look like a variable? Or should I call a function to retrieve that data? Suppose the data isn't actually stored in the object, but is an external resource?

    Yes, it can be aestheticly pleasing to be able to write code that avoids overt function calls, but the flip side is that you then have derived attributes that look different from innate attributes, or you have to maintain the derived attributes in sync with changes to the innate attributes, further confusing the matter. I take it to be somewhere between "better" and "no worse" to have to make explicit method calls to set/get attribute-like properties of an object.

    yours,
    Michael
      Hi,

      I think is some confusion arising form our differing ideas of "attribute".

      An attribute is essentially a variable with possibly some runtime enforced restrictions so it should be accessible just like any other variable.
      That is needlessly restrictive, and the conclusion does not follow from the premise. Suppose you have a timer that is counting up/down. You may have, as an "attribute", the elapsed time/time remaining. Should that look like a variable?

      You changed the premise (widened the meaning of "attribute") it's no surprise that the conclusion no longer follows.

      A timer shouldn't look like a variable because it doesn't behave like a variable. Trying to put a variable-like interface on something that doesn't behave like a variable is just confusing and a bad idea and I never suggested that.

      My definition was needfully restrictive - in order to reach my conclusion. If your idea of an attribute includes things that don't behave like variables then please run

      perl -pe 's/(attribute)/behaves-like-a-variable-$1/g
      on my previous comments.
        Howdy!

        It's not that I "changed" your premise so much as I disagree with your premise (and, implicitly, the conclusions you draw from it).

        In the context of OO and objects, I take "attribute" to refer to data contained within an object. Quite often, it is a simple variable-like thingy, but it is not necessary that fetching the value of an attribute be idempotent. If an object has behavior, and that behavior is autonomous, then my scenario does hold.

        Thinking in shell terms, consider the variables like RANDOM, SECONDS, etc. They change out from under you in a similar manner.

        Besides, $o->foo isn't a variable. It's a CODEREF. If it's an lvalued CODEREF, then it can masquerade as a variable, and that can be useful, or could be if lvalue subs weren't so limited in what they can do (not to mention making it impossible to use the debugger). ${$o->foo} *would* be and look like a variable, but then you have those extra curly braces cluttering things up. *That's* what you should be comparing, and I find the aesthetics unfavorable.

        yours,
        Michael