From: Dmitry A. Kazakov on
On Mon, 06 Aug 2007 18:56:29 GMT, Daniel T. wrote:

> John Carter <joNhOn.ScPaArMteErV(a)EtRait.co.nz> wrote:
>
>> ie. Ways in which bad designs allow us to subtly bypass the invariant
>> protection.
>
> One of my favorite examples:
>
> struct Point {
> int x;
> int y;
> };
>
> class Rectangle {
> public:
> Point& getTopLeft();
> Point& getBotRight();
>
> // invariant:
> // getTopLeft().x < getBotRight().x &&
> // getTopLeft().y < getBotRight().y );
> };
>
> void fn1( Point& p ) {
> p.x = 455;
> }
>
> void fn2( Rectangle& r ) {
> fn1( r.getTopLeft() );
> }
>
> Was the Rectangle object's invariant broken? Maybe, maybe-not...

The design is broken. In this design, there is a getter/setter pair
represented by getTopLeft(). The setter of this pair violates the
invariant.

> There
> is nothing inherently wrong with the two functions, however in
> combination, they are forcing a change in the state space of the
> rectangle without proper permission.

Yes and a proper design implies that no any combination can break the
invariant, as DbC requires. The program above is simply incorrect from DbC
stand point. Though it can be correct in a wider sense, without DbC.

> However, most languages don't have the concept of a "constant
> reference".

This is irrelevant. The way getter/setter are implemented is up to the
compiler. This cannot influence program correctness. In your example, the
compiler could well do copy-out/copy-in for getTopLeft(), which by the way
will be by wide margin more effective on most modern processors, than using
references. It is a big optimization problem in C++, that references are
published. One should never ever do that in presence of CPUs with
multi-level cache. There are lots of object for which you just cannot get
the address of. Or consider a massively networking application with
Rectangle on a different host. What is Point&?

--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de