Re: Opinions on the Law Of Demeter

From: Daniel T. (postmaster_at_earthlink.net)
Date: 11/06/04


Date: Sat, 06 Nov 2004 17:29:51 GMT

Nicholls.Mark@mtvne.com (Mark Nicholls) wrote:
> "Daniel T." <postmaster@earthlink.net> wrote:
> > "Mark Nicholls" <nicholls.mark@mtvne.com> wrote:
> >
> > [between Mark Nicholls and Daniel T.]
> >
> > > > > > // Python
> > > > > > def foo( rect ) {
> > > > > > rect.topLeft().set_x( 5 )
> > > > > > assert rect.top() == 5
> > > > >
> > > > > ooo python...I'll try to interpret.
> > > > >
> > > > > This is a client method operating on a rectangle? with the *client*
> > > > > asserting what it expects the behaviour of rectangle to be....to me
> > > > > that's
> > > > > not completely sensible.
> > > >
> > > > Not quite, the point is that the client assumes that the object
> > > > returned
> > > > by topLeft is not computed, but is an object stored in the rectangle.
> > > > But you are essentially correct.
> > >
> > > "the client assumes that the object returned by topLeft is not computed"
> > >
> > > I think this is my problem....it should not make any such assumption.
> >
> > By saying that, you are advocating LoD.
>
> Yes I suppose I am, I've tied myself in a knot.
>
> hmmmm, let me talk to myself for a minute.....
>
> the fact that top exists and is obviously dependent on TopLeft....and
> this would be explicit to the client in the
> pre/post/conditions/constraints on the inteface.....correct?
>
> I think from my perspective how do I know that the above
> implementation of rectangle is sensible or not, Point could implement
> some sort of observer pattern, and rectangle would be updated of any
> change to Point, even though it would appear at first glance that
> rectangle has no way of knowing what's going on....how does the client
> know, surely it must assume that the specification is 'safe'. So it
> should make no assumption about the implementation except that it is
> safe and that the implementation satisfies the conditions in the
> specification.

Let's think about that for a bit...

-- Eiffel code
class POINT
creation
   make
feature
   x: INTEGER
   y: INTEGER

   make( x0, y0: INTEGER ) is deferred
      ensure x = x0 and y = y0
   end

   setX( v: INTEGER ) is deferred
      ensure x = v
   end

   setY( v: INTEGER ) is deferred
      ensure y = v
   end
end

class RECTANGLE
creation
   make
feature
   topLeft: POINT
   botRight: POINT
   top: INTEGER
   left: INTEGER
   bottom: INTEGER
   right: INTEGER

   make( x, y, w, h: INTEGER ) is deferred
      ensure
         left = x - w / 2
         top = y - h / 2
         right = left + w
         bottom = top + h
   end

   invariant
      topLeft.x = top and topLeft.y = left
      botRight.x = bottom and botRight.y = right
      top < bottom
      left < right
end

Given the above interfaces, is it possible to write a Point class that
implements some sort of observer pattern? Let's say client code does
this:

   method( r: RECTANGLE ) is do
      r.make( 0, 0, 4, 4 )
      r.topLeft.setX( 12 )

The point would have to notify the rectangle of the change, and the
rectangle would have to modify its 'bottom' to some number greater than
12. I guess this is possible, however what number should 'bottom' be set
to? 13, 16, and 26 are all valid... Would this be a reasonable
implementation? I don't think so...

> Thus it's not that LoD is bad (assuming my interpretation is correct,
> which I think Elliott would content it may not be), but that the onus
> is on the wrongf party, i.e. not the client but the service provider.

> > > > > yes, but that to me is a symptom of a poor implementation, I wouldn't
> > > > > blame
> > > > > the client code.
> > > >
> > > > Blame whoever you wish, the fact remains that if client code mutates
> > > > the
> > > > object returned by topLeft the code may work fine... until the
> > > > programer
> > > > of the Rectangle class changes the implementation.
> > >
> > > If it is changes in such manner that it changes pre/post/constaints then
> > > its
> > > a dangerous route. It is in general ignorant of any client imlpementation
> > > and cannot assume people have nicely obeyed LoD and it's safe.
> >
> > Unfortunately, in many languages writing safe code requires heroic
> > effort and/or has unacceptable runtime costs. Such that obeying LoD is
> > easier than protecting the code from itself.
>
> OK, I can buy it as a sort of "life's hard, there are tradeoffs, and
> its sensible to do ABC"....but currently I wont buy it as a theoretic
> utopian truth, like Liskov or specification theory, or even high
> cohesion and low coupling.

As I said to HS, LoD is an OOP issue where life is hard and there are
tradeoffs. One ideal is that no methods have ensure clauses (ie they
make no guarantees to the client at all.) Unfortunately, in many cases
the state of an object is highly dependent on the state of its
sub-objects, and that object cannot (even theoretically) accept
arbitrary changes to those sub-objects.

On of the purposes of a class is to limit the allowed states of its
sub-objects. The Rectangle class is an example of this; top, left,
bottom, right, topLeft and botRight can't be just any values, they are
all limited based on the state of other objects that they know nothing
about, as such Rectangle objects can't allow just anyone unrestrained
access to those sub-objects.

Ultimately, we are in agreement. A class that contains invariants that
restrict the states of its sub-objects should respond to client requests
for a sub-object by either wrapping it in an adaptor that restricts what
the client can do with the sub-object, or provide a copy of the
sub-object to the client.



Relevant Pages

  • Re: Full Screen?
    ... You can have a form full screen event if it has thick border and caption. ... attention on the requirement that the CLIENT RECT has to be that big. ... If you meet those requirements Windows will hide the taskbar for you. ... The problem is how to calculate the bounding rectangle of the Form in a way ...
    (microsoft.public.dotnet.framework.windowsforms)
  • Re: border surrounding an owner-drawn listbox
    ... you can't do this by drawing the client rectangle; you need to get a window ... I can change the shape of a button using SetWindowRgn, but a listbox appears to ... Increasing the clipping rectangle will do no good, because it applies only to the client ... and you can't draw outside the client area. ...
    (microsoft.public.vc.mfc)
  • RE: Updating DB with large collections
    ... Large sub-objects –that is an object which is contained in the main object ... this seems like a complex solution to what I imagined should be quite common ... These entities are being sent to the client - where the user might ... I've tried to serialize my arraylists - both ...
    (microsoft.public.dotnet.distributed_apps)
  • Re: Opinions on the Law Of Demeter
    ... the point is that the client assumes that the object returned ... but is an object stored in the rectangle. ... > on the servicing class to implement in such a way as to not breach it's ... the fact remains that if client code mutates the ...
    (comp.object)
  • Re: Understanding WM_NCCALCSIZE
    ... In this case you should adjust the client rectangle to be some sub-rectangle ... of the window rectangle and return zero. ... my control is a container control and not a simple control. ...
    (microsoft.public.dotnet.framework.drawing)