Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

Re^2: OOP's setter/getter method - is there a way to avoid them?

by mr_mischief (Monsignor)
on Nov 04, 2015 at 18:36 UTC ( #1146929=note: print w/replies, xml ) Need Help??


in reply to Re: OOP's setter/getter method - is there a way to avoid them?
in thread OOP's setter/getter method - is there a way to avoid them?

What you're saying, in short, is to take responsibility for implementing the actions taken on your object rather than foisting that responsibility onto code outside the object?

  • Comment on Re^2: OOP's setter/getter method - is there a way to avoid them?

Replies are listed 'Best First'.
Re^3: OOP's setter/getter method - is there a way to avoid them?
by BrowserUk (Patriarch) on Nov 04, 2015 at 20:18 UTC
    What you're saying, in short, is to take responsibility for implementing the actions taken on your object rather than foisting that responsibility onto code outside the object?

    Yes, but also more than that.

    The use of accessors & mutators does not necessarily imply that. For example, my BankAccount example might be implemented something like this:

    sub new { my %account; ... return bless \%account; } sub getBalance { my $self = shift; return $self->{balance}; } sub setBalance { my( $self, $newBalance ) = @_; $self->{balance} = $newBalance; return; } sub transact { my( $self, $amount ) = @_; my $newBalance = $self->getBalance() + $amount; if( $amount < 0 ) { ## withdrawal if( $newBalance > 0 ) ) { $self->setBalance( $newBalance ); } elsif( $newbalance > $self->overdraftFacility() ) { $self->setBalance( $newBalance ); } else { die 'Overdraw attempt'; ## raise exception; allow caller t +o deal with the problem } } else { ## deposit $self->setBalance( $newBalance ) } return $newBalance. }

    But the point to note here is that getBalance() & setBalance() serve no purpose. There is no purpose in performing any further validity testing within those methods as they should never be called from outside; and whenever they are called from inside, all validity checking required or possible should have already taken place.

    So every use of those methods can be directly and correctly substituted with inlined, direct access to the object attributes; thus they are pure overhead for no benefit; and with the very great downside of breaking encapsulation by exposing the internal attributes to the outside world via the very accessors that are apparently intended to ensure it!

    The same applies to pretty much all other accessors and mutators, with the very rare exception of when it makes sense to have classes of objects that are nothing more that bags of associated variables. And I do mean, very rare.

    There are only two arguments that even vaguely make sense for the provision of accessors:

    • The use of accessors -- internal to the class -- simplifies the (potential future) process of changing the underlying storage of the class. Eg. Moving from a hash-based to array-based (or vice versa) class implementation.

      Sounds cool; but in nearly 30 years of writing and using OO classes; I've never seen an occasion where this was necessary without it also requiring so much other redesign that the savings attributed to the use of accessors would simply be lost in the noise of the overall re-work effort.

      In the greater scheme of things, imposing a recurring, unnecessary, and avoidable fixed overhead on every use of a class in every application that uses or reuses it, in the forlorn hope that you might gain some insignificant benefit from it at some point in the future that in 99% of cases will never arrive is the absolute height of the programmer arrogance that their time is more valuable than that of their 10s, or 100s, or millions of users.

      The arrogance that it is worth the recurring imposition of overhead upon every run; affecting every program that uses the code; and every user that uses those programs; just in case it might save them (the programmer) a few minutes at some unspecified point in the future.

    • That they simplify the process of extending (subclassing) the class.

      I've seen this argument put forward, but never seen any evidence that it is so. It seems to me to be just as easy to subclass a class that doesn't use accessors as it is one that does. And further more, the absence of the additional overhead of accessors in the parent class mean that subclasses also benefit.

    To date, and I've been arguing this point for most of my career, the provision of externally accessible accessors and mutators is a direct contravention of the design goals and aspirations of OO design. And the use of internal use only accessors and mutators -- where the language allows this -- is pure avoidable overhead with only a theoretical potential benefit that in 30 years I've never seen realised.

    In compiled languages with decent optimising compilers; that overhead is minimal as the accessors and mutators get in-lined at compile time; but in a interpreted languages without that benefit and without a mechanism to prevent those accessors being used externally to the class; they are not just overhead, but severe code-smell.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority". I knew I was on the right track :)
    In the absence of evidence, opinion is indistinguishable from prejudice.

      Using the bank account example, though, what if I just want to check my balance? What if I just want to check the date of account creation, or verify my account number? No actual mutation is necessary, but it would be handy to access those values. There wouldn't be a need to mutate those directly, but accessing them without making a deposit or withdrawal should be possible. I suppose you could have a method called query_balance that returns the balance and also updates a log of the query.

        Indeed. There are always going to be some attributes that need to be queried. Further, there are some attributes that need to be set directly and in isolation. Eg. If you move the address need to be updated. If you change your pin. Etc.

        Of course, the former is likely a part of a Customer Class; and validation of the address is likely performed by a different processing application long before that information is wrapped up in a transaction and applied to the actual Customer record.

        And the latter is likely part of a CreditCard class; and again validation and verification checks performed outside of the process that updated the master records.

        But the point holds; accessor and mutator methods should be added deliberately as a designed requirement for those attributes that require them for the functional operation of the class; not generated automatically regardless of the need.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority". I knew I was on the right track :)
        In the absence of evidence, opinion is indistinguishable from prejudice.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1146929]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others taking refuge in the Monastery: (2)
As of 2022-11-26 13:17 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Notices?