[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: the benefits of immutability
On Mittwoch, August 20, 2003, at 03:46 Uhr, Vadim Nasardinov wrote:
> Pascal Costanza wrote:
> > public boolean equals(Object that) {
> > if ((this.class != that.class) &&
> > this.class.isAssignableFrom(that.class))
> > return that.equals(this);
> >
> > if (!(that instanceof Subclass)) return false;
> >
> > return super.equals(that) && (this.state ==
> ((Subclass)that).state);
> > }
>
> Clever. I can't find any holes in this, as far as the equivalence
> relationship is concerned. (One minor nitpick is that you have to
> test for nullity, before you can dereference "that".)
Right.
> If this approach is used for implementing internally facing
> package-scoped classes that are not part of the exported API, then
> everything is fine. If classes like this *are* part of the exported
> API, then users of such a class may be in for a surprise. Let's
> ground this in slightly more concrete terms. Suppose the following
> classes follow the above approach and are part of the API that you
> ship as part of your product.
>
> public class Circle {
> private int radius;
>
> /**
> *@pre radius > 0
> **/
> public Circle(int radius) {
> if ( radius <=0 ) { throw new IllegalArgumentException(); }
> this.radius = radius;
> }
>
> public int getRadius() {
> return radius;
> }
> // the rest of the methods omitted for brevity
> }
>
> Suppose Barbara is a user of your product who writes code against the
> Circle API. In her world, any circle with a radius of 3 is equal to
> any other circle with a radius of 3. When Jeannette is hired she
> extends Circle as follows.
>
> public class ColoredCircle extends Circle {
> private Color color;
>
> public ColoredCircle(int radius, Color color) {
> super(radius);
> this.color = color;
> }
>
> public Color getColor() {
> return color;
> }
> }
>
> Since Jeannette reads ll1-discuss on a regular basis, she dutifully
> follows the method you suggested. Barbara's code no longer works,
> because color-blind circles are never equal to colored circles of the
> same radius. A circle with a radius of 3 is not the same thing as,
> say, a circle with a radius of 3.
Of course, I expect Jeanette to think about what she does and write the
following code:
public boolean equals(Object that) {
if (that == null) return false;
if ((this.class != that.class) &&
this.class.isAssignableFrom(that.class))
return that.equals(this);
return super.equals(that) &&
(that instance of ColoredCircle ?
this.color == ((ColoredCircle)that).color : true);
}
> Which brings us back to the the original point: writing externally
> facing classes that allow subclassing is hard.
I think the really issue here is that Java doesn't have multi-methods.
Both tricks I have introduced in this example are hand-coded
simulations of multiple dispatch.
Pascal