in reply to The fallacy of the *requirement* for read-only instance variables.
When I use an object, I usually don't care if a method which receives no argument and returns a value is an attribute accessor or not. Neither should I -- that's the beauty of OO, as a user of a class I don't have to care.
Consider Date::Simple, one of my favorite CPAN modules. It has several ways to create an instance of that class - you can either pass in a date in YYYY-MM-DD format, or I can pass in year, month and day, or I can create one as result of an arithmetic operation, or just get it from Date::Simple::today().
On the other I can retrieve several pieces of information from such an object: day, month, year, day of year, day of week and so on. Some of them might be read-only accessors of instance variables, other probably aren't - but I don't have to care.
If one of those methods is an accessor, I'm pretty sure it doesn't meet all three of your criteria for being "legitimate", and yet I'm pretty sure it doesn't indicate any of the four fallacies you listed: it doesn't force me as the caller to perform any extra action, a Date is surely not a catch-all object, it should surely be a class (otherwise arithmetic with it would be very inconvenient), and I can't see a case of premature optimization either.
So why are these methods legitimate, even if you argue that some of them probably aren't, just by because they are ROIAs?
Because they hide implementation details I couldn't care less about. If Date::Simple calculations returned hashes with some data points (say year, month, day), I'd be forced to remember which data is stored in the hash, and which must be calculated from these values (for example day of week). Such a non-uniform interface would put cognitive load on the user - something that should be avoided, even if it means a few extra method calls for obtaining some data.
These accessors also give you a consistent interface when the internal representation changes, thus decoupling API from implementation - another plus.
Now, some will argue: "But what of the caller passes the object to some other piece of code that doesn't have access to the value used during initialisation?". And the answer is, that if the caller can pass the object to that other code, it can equally well pass the value to that other code directly rather than via the object.
And then: "What if the caller has many values that it wants to pass to the other code? Isn't encapsulating them into a data-only object and passing its handle to that other code better than passing a bunch of discrete variables?". And the answer is, how is that better than putting the variables into a simple data structure like a hash or array and passing a reference to that to the other code?
There's also a middle ground: a routine might need to return both some "dumb" data, and an "active" object. If it makes sense for the abstraction in question, it might make sense carrying that "dumb" data in the "active" object, instead of placing the burden on the caller to deal with both of those separately.
For a (public) read-only instance variable (ROIA) to have a value, it must be assigned one. This may happen in one of two ways.
There is a third case: a value might be derived both from values passed by the caller and from "impure" (in the functional programming sense) source like IO and randomness. In this case it might be impossible to obtain the same answer twice, even if the computation isn't expensive. Thus storing data in an attribute might not be just caching, but required for consistency.
Finally if the object needs a value for further calculations, it can just as well make it available for the caller - yet modifying it might invalidate previously calculated data.
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^2: The fallacy of the *requirement* for read-only instance variables.
by BrowserUk (Patriarch) on Apr 17, 2011 at 14:41 UTC | |
by moritz (Cardinal) on Apr 17, 2011 at 16:24 UTC | |
by BrowserUk (Patriarch) on Apr 17, 2011 at 19:20 UTC | |
by moritz (Cardinal) on Apr 17, 2011 at 20:36 UTC | |
by BrowserUk (Patriarch) on Apr 17, 2011 at 21:45 UTC | |
| |
by ikegami (Patriarch) on Apr 19, 2011 at 22:35 UTC |