Prev: JFileChooser applet doesn't work on all platforms
Next: Is there a 'Filter' or 'Predicate' interface anywhere in theJDK?
From: Tom Anderson on 28 Jun 2010 16:43 On Mon, 28 Jun 2010, Lew wrote: > Tom Anderson wrote: > >> And of course, it goes without saying that: >> >> Hand.getBird().equals(Collections.asList(Bush.getBird(), Bush.getBird())) > > That works as a pun, but as Java code would fail to yield 'true' under > conformant implementations of 'equals()'. I forgot to mention that Bird implements List<Bird>. Weird, but there you go. tom -- Fitter, Happier, More Productive.
From: Tom Anderson on 28 Jun 2010 16:52 On Mon, 28 Jun 2010, Lew wrote: > Arne Vajh?j wrote: >>> And in general those figure examples often lead to problems like the >>> wellknown Rectangle versus Square problem. > > ClassCastException wrote: >> A problem that goes away when you make the durn things immutable. > > Not really, but it does go away when you make the classes final. You mean both of them? Then you either have to introduce a common base class ParallelRightQuadrilateral, or be unable to write code that manipulates boxes uniformly. Making Square a subtype of Rectangle is still very attractive from a programmer-friendliness point of view. Immutability is one way of overcoming the problems that introduces - and it really does solve them. Squares are only non-Rectangular when they'r mutable, because it's only their mutability that is not a superset of Rectangle's tom -- Fitter, Happier, More Productive.
From: Lew on 28 Jun 2010 17:30 Tom Anderson wrote: >>> And of course, it goes without saying that: >>> >>> Hand.getBird().equals(Collections.asList(Bush.getBird(), Bush.getBird())) > Lew wrote: >> That works as a pun, but as Java code would fail to yield 'true' under >> conformant implementations of 'equals()'. > Tom Anderson wrote: > I forgot to mention that Bird implements List<Bird>. Weird, but there you > go. > That still would not be conformant, because the requirement for 'List#equals()' is, "Returns true if and only if the specified object is also a list, both lists have the same size, and all corresponding pairs of elements in the two lists are equal." A List with one element cannot be equal to a List with two elements under a conformant 'equals()'. Besides, it's not true that a bird in the hand is *equal to* two in the bush, it's that a bird in the hand is *worth* two in the bush. -- Lew
From: Lew on 28 Jun 2010 17:31 ClassCastException wrote: >>> A problem that goes away when you make the durn things immutable. > Lew wrote: >> Not really, but it does go away when you make the classes final. > Tom Anderson wrote: > You mean both of them? Then you either have to introduce a common base > class ParallelRightQuadrilateral, or be unable to write code that > manipulates boxes uniformly. Making Square a subtype of Rectangle is still > very attractive from a programmer-friendliness point of view. Immutability > is one way of overcoming the problems that introduces - and it really does > solve them. Squares are only non-Rectangular when they'r mutable, because > it's only their mutability that is not a superset of Rectangle's > Oh, yeah. You're right. -- Lew
From: ClassCastException on 29 Jun 2010 00:21 On Mon, 28 Jun 2010 20:31:40 -0700, Peter Duniho wrote: > Arne Vajhøj wrote: >> [...] >>> It's debatable whether one really needs methods in the type that >>> return modified versions of the original. But assuming one does, >> >> It is rather common to have such. The Java API itself has some >> important ones. > > Really? Where is the Square type in the Java API that inherits > Rectangle, never mind the immutable version that returns modified > versions of the original? > >>> could easily enforce Rectangles and Squares, either by throwing >>> exceptions if misused (which is actually possible even with mutable >>> types, though would involve more work), or by providing methods that >>> always return the right kind of type (Square if the new dimensions are >>> equal, Rectangle otherwise). >> >> What should the formal return type be? > > Whatever you want it to be. One option is Rectangle. If it matters > whether the resulting type is a Square (e.g. Rectangle.FitInSquare()), > you can check and cast. > > If you want the return type to be Square, you have to throw an exception > if someone tries to return a non-Square from a Square. Or you provide > an API that only returns a Square (e.g. adjusts both dimensions by > identical amounts). > >> The sub class can return the super class but not the other way around. > > Rectangle can return a Square instance and Square can return a > Rectangle. I have no idea why you think you can't do it that way. > > Of course, whatever API is chosen, it needs to make sense in context. > But there's no fundamental reason Rectangle can't return a Square. > >>> There's no reason for weird behavior to exist. Just don't implement >>> weird behavior. :) >> >> Difficult to avoid if the classes should have rich functionality. > > Now you are adding requirements not originally stipulated. No one said > anything about "rich functionality", nor is it even clear what is meant > in the case of the Square/Rectangle example. > > Pete How about making the example more concrete, then. public class Rectangle { protected final double l; protected final double t; protected final double w; protected final double h; public Rectangle (double left, double top, double width, double height) { if (width <= 0.0) throw new IllegalArgumentException(); if (height <= 0.0) throw new IllegalArgumentException(); l = left; t = top; w = width; h = height; } // getters go here, and getRight and getBottom public Rectangle getScaledInstance (double scaleFactor) { if (scaleFactor == 0.0) throw new IllegalArgumentException(); // top left corner is center of scaling transform's effect if (scaleFactor < 0.0) return new Rectangle(l + w*scaleFactor, t + h*scaleFactor, -w*scaleFactor, -h*scaleFactor); return new Rectangle(l, t, w*scaleFactor, h*scaleFactor); } public Rectangle getWithWidth (double newWidth) { if (newWidth <= 0.0) throw new IllegalArgumentException(); return new Rectangle(l, t, newWidth, h) } public Rectangle getWithHeight (double newHeight) { if (newHeight <= 0.0) throw new IllegalArgumentException(); return new Rectangle(l, t, w, newHeight) } public Rectangle getMoved (double newLeft, double newTop) { return new Rectangle (newLeft, newTop, w, h); } } public class Square extends Rectangle { public Square (double left, double top, double size) { super(left, top, size, size); } public Square getScaledInstance (double scaleFactor) { if (scaleFactor == 0.0) throw new IllegalArgumentException(); // top left corner is center of scaling transform's effect // w = h = size if (scaleFactor < 0.0) return new Square(l + w*scaleFactor, t + h*scaleFactor, -w*scaleFactor); return new Square(l, t, w*scaleFactor); } public Square getMoved (double newLeft, double newTop) { return new Square (newLeft, newTop, w); } } The "copy-mutator" methods that would preserve squareness return Squares. The ones that could produce non-square rectangles aren't even overridden, and return Rectangles. This works, though it's possible to get square Rectangles that are not Squares. Making the constructor protected, adding a public factory method that calls it normally but only after if (width == height) return new Square(left, top, width);, and changing the "copy- mutators" to call this factory method would address this, if one felt it necessary. Of course if there's any problem with the above let me know and I'll try to address it.
First
|
Prev
|
Next
|
Last
Pages: 1 2 3 4 5 Prev: JFileChooser applet doesn't work on all platforms Next: Is there a 'Filter' or 'Predicate' interface anywhere in theJDK? |