On Mar 12, 12:43 pm, Bart van Ingen Schenau <b...@[EMAIL PROTECTED]
>
wrote:
> Daniel T. wrote:
> > Bart van Ingen Schenau <b...@[EMAIL PROTECTED]
> wrote:
> > > Chris ( Val ) wrote:
>
> > Code example under consideration:
>
> > class Foo {
> > public:
> > int getValue() const;
> > int setValue( int v );
> > // ensure: result == old getValue() && getValue() == v
> > };
>
> > > I would regard such a setter that returns the previous value as
> > > perfectly valid OOP, if two conditions are met:
> > > 1. Having the setter at all does not blatantly violate the
> > > principles of OOD.
> >
> > It blatantly violates the Command-Query Separation principle.
>
> Can you give me a pointer to a resource where it is stated that this is
> a fundamental principle of OOD?
Meyer, Bertrand. Object-Oriented Software Construction, 2nd Edition.
Prentice Hall, 1997
Good book. Now, are you going to pull the "no *true* Scotsman" fallacy
on me?
> And if I understand the principle correctly, a setter like
> bool setValue( int v );
> would also be in violation, because it both changes the state and
> returns information about the state.
Depends on what the ensures clause is, but if the function's post-
condition is "result == true ? getValue() == v : getValue() == old
getValue()" then yes, it breaks the rule.
> Even throwing an exception would violate a strict interpretation of this
principle.
An exception should only be thrown if the contract cannot be
guaranteed. So no, an exception tells you nothing about the state of
the object.
> > However, the method *is* the sole means of retrieving that which it
> > retrieves (the value of getValue() before the last time setValue() was
> > called,) and it only works once. Referential transparency is broken.
>
> It does not work only once.
> You can call setValue() as often as you want and each time the call
> returns the value as it was prior to that call.
Really?
if ( p.setValue( 7 ) > 10 )
cout << "old value was " << ??? << '\n';
You can't determine the old value at the "???" point. Once you call
setValue, you have no means of finding out from the object what the
return value was (or as you state below, there is no corresponding
getter for retrieving the value without changing it.) You would be
forced to create a tem****ary to hold the value.
> Referential transparency is indeed broken, because setValue() does not
> claim to be a query operation.
The OP specifically used it to query the state of the object, he
returns the value spicifically so he *can* make the query. Of course
the function claims to be a query operation.
> To me, it is acceptable to return the old value from a setter if
> - having the setter at all does not violate encapsulation, and
> - there is a corresponding getter for retrieving the value without
> changing it.
There is no corresponding getter for retrieving the value that
setValue returns without changing it. The value that 'setValue'
returns cannot be retrieved though any getter.
Again, by your own rules, the function isn't acceptable.
> > > > Some setters are written to return a 'boolean' value to signal
> > > > either success or failure, but even that is debatable in some
> > > > cir***stances, when compared to throwing an exception.
> > >
> > > If it is actually a setter, and not a function that happens to set
> > > some values as part of a larger operation,...
> >
> > That is getting into implementation details that the interface
> > shouldn't expose...
>
> Just about any interface exposes this kind of information, if only by
> the naming of the identifiers.
Really?
class Foo {
public:
virtual int getX() const;
virtual void setX( int x );
// ensure: getX() == x
};
How does the above function signature tell you *anything* about
whether it is a "real setter" or just a function that happens to set
some values as part of a larger operation?
For all you know, setX uses a BSD socket to send data half-way around
the world.
> > From the client's (user of the cl*****) point of view, there should be
> > no difference between a command that "is a real setter" and a command
> > that "happens to set some values".
>
> For the person writing the client code, it will often be possible or
> even easy to make the distinction, by looking at the names of the
> functions and the interface do***entation.
That would be very poorly written do***entation if that were the case,
and if the client needs to make such a distinction, then the code is
poorly written as well. The whole point of the interface is so you
don't have to know such things.


|