Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

This is sort of a classic example (with the behavioral expectations of the interface that you have stated in the text, which are not expressable as a constraint in Go code -- or in most languages where the LSP is a concern -- but which often would be documented as an expectation of the parent class in a class-based inheritance system, and would usually be expected from the naming of the class/interface) of why mutability is problematic in terms of the LSP, as its not problematic at all if the signature is:

  type Rectangle interface {
        SetHeight(int) Rectangle
        SetWidth(int) Rectangle
        GetHeight() int
        GetWidth() int
    }
Though, perhaps more than the LSP, this should be a textbook illustration of why representations of mutable objects in a program should not be named after entities in the domain whose essential identity is associated with one or more attributes that are mutable in the representation.


perhaps more than the LSP, this should be a textbook illustration of why representations of mutable objects in a program should not be named after entities in the domain whose essential identity is associated with one or more attributes that are mutable in the representation.

Yes, in the example I gave, I agree. Certainly objects such as Rectangles and Squares should be modeled as immutable value objects. Immutability solves the problem completely. The example would perhaps be better if instead of Rectangles and Squares it talked about Windows and FixedAspectWindows.


> The example would perhaps be better if instead of Rectangles and Squares it talked about Windows and FixedAspectWindows.

But, here, I think it should be quite clear that the solution is to make clear that independence of the dimensions on the two axes is not a guarantee provided by the Window interface or class. Interdependence of a particular form is guaranteed by FixedAspectWindow, and there might be a similar subtype of FlexibleAspectWindow that guarantees independence, but Window itself should not make any guarantee (and should, if necessary for clarity, expressly disclaim such a guarantee.)

But one thing I think that it is worth highlighting is that the fact that some guarantees of a type are expressable and enforceable through code does not ensure that all are, and the LSP most critically applies to those that are not (since those that are expressed and guaranteed through code won't ever be a problem), but to those that are communicated through other mechanisms, including those communicated implicitly through naming.


> including those communicated implicitly through naming

As an aside, this is an aspect of what I like about choice of names like "Functor" and "Monoid". There is very little room for ambiguity.

Further aside... In Haskell, there's still "do we include operational equivalence?" and "are we considering equivalence only up to bottom?". But at least the guarantees around the semantics for non-bottom values are reliably uncontroversial.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: