Re: On getters/setters (to Daniel T.)

From: Daniel T. (postmaster_at_eathlink.net)
Date: 02/06/04


Date: Fri, 06 Feb 2004 04:11:36 GMT

Ilja Preuß <preuss@disy.net> wrote:

> Daniel T. wrote:
> > "Ilja Preuß" <preuss@disy.net> wrote:
>
> >>>>> In any case, we aren't
> >>>>> talking about "the design" as a whole, we are talking about
> >>>>> wether a particular method is appropriate or not.
> >>>>
> >>>> And that seems to be the problem of this discussion: I *was*
> >>>> talking about the former, and I understood Ron to talk about it,
> >>>> too. That's what "accessors are code smells" means: they are a
> >>>> hint to the fact
> >>>> that there might be something inappropriate with the design as a
> >>>> whole.
> >>>
> >>> Humm... The assumption seems to be that accessors are a hint because
> >>> there is something inherently wrong with some of them.
> >>
> >> No. The assumption is that there is something potentially wrong with
> >> using them too much.
> >
> > With *using* them... Wouldn't it then be better to focus on the client
> > code and how it uses the server methods, rather than focusing on how
> > the server happens to implement those methods?
>
> Yes, you are correct. The focus is on how the methods are used. The
> implementation is just a hint to potentially problematic uses. Taking a look
> at the implementation is valuable not because it points directly to the
> problem, but because it is so highly visible and often enough points to
> possible design improvements to care about it. YMMV, of course.
>
>
> >>>> In fact, I don't think that you can tell wether a method is
> >>>> appropriate without taking a look at how it gets used. (You might
> >>>> be able to tell wether it is *implemented* appropriately, but not
> >>>> wether its *existence* is appropriate.)
> >>>
> >>> I will agree with this completely, however how a method is used has
> >>> *nothing* to do with how it is implemented.
> >>
> >> Mhh, I have to think about this...
> >
> > Yes, please do. It is my strongest argument yet.
>
> I think we are focussing too much on single methods in this discussion.
>
> It's obvious to me that in most systems we do have data because we want to
> work on it. It seems to be a good idea to put operations near to the data
> they are working on (that's the idea of encapsulation, as I understand it).

We have a different idea of encapsulation. I understand it as ensuring
invariants cannot be broken. A by-product of this is that
member-variables must be protected from change by code that isn't in
charge of maintaining the invariant.

> If we have a class which basically presents its data to the outside, it
> might be reasonable to conclude that its clients are working on that data.

Or the clients need that data to help determine their own state? I would
say that this is a more reasonable conclusion.

> >>> By putting this "trimRangeHeighTo" outside of the range class, I can
> >>> change the implementation of the class without having to worry about
> >>> breaking the "trimRangeHeighTo" method/function.
> >>
> >> Do you? How does putting it on a different class protect it from
> >> breaking?
> >
> > Because it allows one to change the implementation of the class
> > without examining the implementation of trimRangeHeighTo (assuming it
> > isn't in the class.)
>
> How does it allow to do that? It seems to me as if code depending on some
> data/other code inherently is coupled to it, indepently of where it resides.
> Again, how does simly moving the code to a different class make it
> invulnerable to changes in the code it depends on?

As I showed with my "trim" example, the code becomes invulnerable
because it no longer depends on implementation assumptions of the class.
This is OO 101 we are talking here.

> > I think it is inherently true, every time you change the
> > implementation
> > of one method of a class, you must at least examine all the other
> > methods to insure that they haven't been broken by the change. If you
> > don't, then I would say you don't have a clear separation of concerns.
> > This doesn't count for client methods though, they are the ones that
> > drive the servers interface, which is what forces the server to a
> > particular implementation.
>
> This doesn't compute to me. Are you saying that the client code can't break
> because of changes in the server as you don't do changes which could
> break client code? That seems to be somewhat circular reasoning to me - I am
> sure I am misunderstanding something.

I'm saying that changes to the interface of a class are (or at least
should be) driven by changes in the clients that use it, not changes in
its implementation. So yes, I'm saying that one should not make changes
to server code that would break client code.

> > Let me present a concrete example. The C++ std::string class has some
> > 120 different methods.
>
> And I guess quite a lot of them would qualify as non-accessors in my narrow
> sense. And a client probably should strive to use those instead of the
> accessors?

How is a client, which is supposed to be ignorant of the implementation
of the servers it uses, supposed to strive to use non-accessors?

> > That's quite a parcel for a class that
> > implements
> > a very single minded and basic concept. Yet, there is no method for
> > trimming whitespace off the ends of strings (something that I have
> > used
> > quite often.) Does that mean I should push to have the method included
> > in the class? Is the class deficient because this method is missing?
> > Of course not, I'm able to implement my own trimWhiteSpace function
> > using
> > the public interface available, and what is more, if the
> > implementation
> > of std::string changes, I don't have to worry, because I'm relying on
> > the (much more stable) public interface to implement my function.
>
> Yes - but the interface is more stable *because* changes to it would break
> its clients! The interface *restricts* the implementation of the server to
> solutions which don't break clients. So the more the interface assumes about
> the implementation, the less flexible you are in implementing the server.

I agree. Where I disagree is that I don't think "getX/setX" methods that
protect the invariant, assume anything about the implementation. As I
have demonstrated numerous times, these methods don't tell us anything
about how the class is implemented.

class Car {
public:
   Color getColor();
};

Nothing in the interface above tells us how getColor is implemented. For
all we know, the method sends signals to an electronic eye that is
pointed at the car and reads data returned from it. There is no
requirement that getColor must be implemented by returning the value of
a member-variable (field.)

> > If I
> > were to implement trimWhiteSpace as a string method, then it stands to
> > reason that I would have to at least examine it's implementation
> > whenever I modify the implementation of string (for example if I
> > switch to COW semantics.)
>
> Yes, of course. On the other hand, you have full control over the
> implementation and therefore are less coupled to your clients.
>
> > Now, it may be that calling my trimWhiteSpace is much more costly in
> > time than if it were implemented using special knowledge that only a
> > member-function (method) has access to, put putting the method in the
> > acutal class gives us just one more method we have to fix if we need
> > to re-implement std::string as a deque (ie a series of discontigious
> > blocks of memory.)
>
> Yes, there is certainly a balance.
>
> > Some of the methods in std::string seem to force it into a particular
> > implementation. For example the method 'c str' and 'data' return a
> > single contiguous piece of memory (a C style array) that contains the
> > entire contents of the string. This implies that the class actually
> > contains the entire contents as a single contiguous block of memory,
> > but
> > that doesn't have to be the case. I could easily present the exact
> > same interface (ie have a 'c str' method) with a completely different
> > implementation. Calling this method would then be much more expensive
> > however because the class would have to allocate the block a memory
> > and
> > set the values of each byte (and then, because we are talking about
> > C++,
> > it would have to track that allocation and delete it when
> > appropriate.) Despite the fact that 'c str' tends to force the
> > implementation, it is
> > still a completely appropriate method to have in a string class
> > designed
> > for C++. Clients *need* this getter, even if it isn't implemented as
> > such.
>
> Quite possible; I don't know enough about C++ to comment.
>
> But you seem to agree that the interface restricts the implementation?

Of course, the implementation must implement the interface! You can't go
doing whatever you want in the implementation, you must provide for your
clients needs.

> Wouldn't you conclude that therefore the implementation you want to use could
> also influence the interface you want to have?

No, the interface I want to have is solely driven by the clients needs
and should have nothing whatsoever to do with the implementation of that
class. As long as clients need the getter, the interface must provide
the getter, and the implementation must be written such that the data is
available. That doesn't mean that the implementation must store the data
of course, but it must be able to provide that data upon request.



Relevant Pages

  • Re: Holub on getters/setters again
    ... > getter/setter interface, you simply can't implement that solution, so it ... code and how it uses the server methods, rather than focusing on how the ... Especially they might hint to clients implementing operations on ... whenever I modify the implementation of string (for example if I switch ...
    (comp.object)
  • Re: Cannot get NAT to route in RRAS
    ... If the server can browse the Internet, the clients should be able to do ... > ADSL Link was set as the Public interface in NAT, ... but the routing table still shows the default gateway ...
    (microsoft.public.win2000.ras_routing)
  • Re: Confusion: Server side creation of CAOs
    ... The you put that additional functions in a new interface. ... >make your server object implement both interfaces. ... >still can use the server the way they used to, and new clients can use ... >the new interface for increased functionality. ...
    (microsoft.public.dotnet.framework.remoting)
  • Re: RAS Server extra IP listing in DNS
    ... But to disable registration for the clients ... properties of demand-dial interface. ... Windows Server - Active Directory ... So that will affect the virtual interface provided for RAS as well? ...
    (microsoft.public.windows.server.active_directory)
  • Re: What doesnt lend itself to OO?
    ... The whole idea that a subsystem is just ... > The first line exists in the server. ... objects between client and server i.e. as far as the client code is ... > external interface is the traditional input interface whose ...
    (comp.object)