Daniel T. wrote:
> 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?
No, because I am starting to think that there might not *be* a "true
Scotsman" here.
To my knowledge, that book does not form an authorative (sp?) definition
of OO, nor do my sources. I don't know if there is any authorative
definition around, so I can't tell if the Command-Query separation is
listed there as a fundamental principle.
>
>> 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.
Depending on the exception-safety guarantee of the function, it actually
does tell something about the state, in the same way that the boolean
return value above does.
>
>> > 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.
Nor can you if setValue did not return the old value, so that argument
does not hold.
> 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.
And is setValue() did not return a value, you would also need to use a
tem****ary or rewrite the code in a different order.
I don't see what your problem is with that.
>
>> 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.
But the function also claims to change the state of the object and a
Query does not do so. Therefor, it can not be a Query.
>
>> 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.
Thanks for trying, but this kind of argument is not going to convince
me.
I think it is best if we agree to disagree on this issue.
>
> 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?
The name "setX" implies that only the conceptually simple operation of
assigning a new value to the property X will take place. Therefor, I
would call that a "real setter".
A function called "drawPicture" on the other hand implies that a more
complex operation takes place.
Bart v Ingen Schenau
--
a.c.l.l.c-c++ FAQ: http://www.comeaucomputing.com/learn/faq
c.l.c FAQ: http://c-faq.com/
c.l.c++ FAQ: http://www.para****ft.com/c++-faq-lite/


|