cast or notNull in my project.
java.util.List<Handle> handles = new ArrayList();
...
ConnectionHandle ch;
ch = cast(handles.get(handles.size()-1));
ConnectionHandle extends Handle
How do you know that the last element has the right type? -- DanielBonniot
The draggable points of a Connection are Handles. The first and the last are connected to flowlets, thats why they are called ConnectionHandles, and the handles in between are EllbowHandles. There can be zero or more EllbowHandles?. I defined it like this. -- AlexGreif
Interesting. Here it is the logic of the system that guarantees the cast will not fail.
I think you could take into account this logic in the types. One possibility is to keep a reference to the handles on both extremities in fields of type ConnectionHandle.
If you wish, you can encapsulate the handles in a Handle class:
class Handles
{
List<Handle> handles;
ConnectionHandle first;
CollectionHandle last;
}
// Some methods to manipulate handles.
--Main.DanielBonniot
Interesting too. But IMO not very nice design, because the class Figure (the super class of all) has the member List<Handle> handles. And I want to store all handles in one List. A Connection has this speciality that it has two types of handles. Besides this I can iterate easily if all Handles are in one List. -- AlexGreif
OK. Then could you add in Connection the two fields, while keeping everything in the list? -- Daniel
Then the info is redundant, and I have to update both. Where do I profit if I introduce two fields? -- Alex
The type information is not redundant. A benefit is that you make sure that there is no cast, that might fail at runtime in some strange condition. On the other hand, it is true that you then need to guarantee that the value in the field is the same as in the list.
If you have a set method in the parent to build the list, then you could override it to set the fields when the index is 0 or length - 1, and the call super.
I agree that the benefit is discutable. An alternative is to use the cast.
In a future version of Nice, I could imagine that you could do:
Hand h = cast(handles.get(handles.size()-1)); assert h instanceof ConnectionHandle; // Now you can use h as a ConnectionHandle.
?Figure figure = getFrontFlowWindowDrawArea().getDrawing().getFigureExcept(
mousePos, this);
if (figure == null) return;
Flowlet flowlet = cast(figure);
Flowlet extends Figure
The problem is now like with ConnectionHandle?. Could you modify the design a bit, so that the type of the expression is Flowlet and not Figure?
No. Figure is the superclass of all drawable Items. Flowlets are items that can be connected together. Connections cannot be connected. Thats why they are Figures.
Here is the class hierarchy:
if (connectorListeners == null) return;
for (Iterator<ConnectorListener> iter = notNull(connectorListeners).iterator(); iter.hasNext();) {
ConnectorListener ltnr = iter.next();
if (figure.getHandles().contains(cast(ltnr))) {
iter.remove();
//println(" deleted: " + ltnr);
}
}
Isn't this code equivalent to the following -- ArjanB
I think Arjan is right, I will test it -- AlexGreif
if (connectorListeners == null) return;
connectorListeners.removeAll(cast(figure.getHandles()));
You need notNull, because connectorListeners is not a local variable. This is explained in OptionTypes. A solution is there too.
What is the type of figure.getHandles() ?
java.util.List<Handle> getHandles() = handles;ConnectorHandle, that extends Handle implements ConnectorListener Interesting. So you have a value of type A, a
List<B> with B extends A,
and you want to know if the value is in the list, right?
We were discussing with Arjan if this is ever needed.
The point is, it can only be true if the value is of type B.
But now I can believe this is really useful.
If it is really this, we will change the type of contains in nice.lang.
After that, you won't need this cast. -- DanielBonniot
I changed the retypings so the cast isn't needed anymore in the next DevelopmentVersion -- Arjan
Another example to show why contains should be contravariant.
<T,U,V | U <: T, V <: T> Set<T> intersection(Set<U>, Set<V>);
intersection<T,U,V>(s1@Set, s2@Set) {
Set<T> res = new HashSet();
if (s1.size() < s2.size()) {
for(U elem : s1)
if (s2.contains(elem)) res.add(elem);
} else {
for(V elem : s2)
if (s1.contains(elem)) res.add(elem);
}
return res;
}
Should I reapply that patch then Daniel? -- ArjanB
OK! Doesn't removeAll also need to get a contravariant type? -- DanielBonniot
Yes but if I'm consistent then should almost all methods of the collection be retyped to get a co/contra-variant type. the methods in Map will get uglier retyping then.
<K, K0, V0, V | K <: K0, V <: ?V0> ?V0 get(java.util.Map<K, V>, K0) = native Object java.util.Map.get(Object);Yes, it makes sense. JSR 14 (Java Generics) does use Object for the key in get. So we are still more strict and safe than them. I don't think it matters too much if the retypings become more complicated, especially if it means they will be usable in more situations. -- Daniel Ok but I'm not sure about one kind of retypings:
<K, K0, V | K <: K0> java.util.Set<K0> keySet(java.util.Map<K, V>) = native java.util.Set java.util.Map.keySet();this is safe because a keyset is read/remove only. -- Arjan Are you not sure it is safe, or if it is useful? I checked the javadoc, it is true that you cannot add elements, so this must be safe. I'm not sure how useful it will be, but it does not harm to do it. Maybe it will turn out useful in some situations. And we can say that Nice allows this, while Java 1.5 cannot! :-) -- Daniel It reminds me that I still should write something about retyping, at least the is no shortage of examples -- ArjanB
getFromConnection(state) {
java.util.List<Connection> followings = this.getFromConnections();
for (int i = 0; i < followings.size(); i++) {
DecisionConnection connection = cast(followings.get(i));
if (connection.getState() == state) {
return connection;
}
}
return null;
}
DecisionConnection extends Connection
Why don't you declare that this.getFromConnections() returns a List<DecisionConnection>? -- DanielBonniot
The code above is in DecisionFlowlet, but this.getFromConnections() is declared in Flowlet that returns Connection objects.
Is getFromConnections reimplemented for DecisionFlowlet? -- DanielBonniot
No. Only implemented in Flowlet class. Thus I have to return a List with the lowest common denom.. --Main.AlexGreif
Should I use :
java.util.List<DecisionConnection> followings = cast(this.getFromConnections());
-- AlexGreif
It's possible, but that's still a cast.
Note that using get on a List in a loop can be bad, in case the List is a linked list: you will traverse n**2 elements, instead of n.
This is ideal for the new for syntax of version 0.7.8:
getFromConnection(state) {
java.util.List<DecisionConnection> followings = cast(this.getFromConnections());
for (DecisionConnection connection : followings) {
if (connection.getState() == state) {
return connection;
}
}
return null;
}
-- DanielBonniot
OOps did I miss that? Is it documented somewhere? -- AlexGreif
I think it's in the changelog only, at the moment.
You see, Arjan, documentation is needed! :-)
-- DanielBonniot
It should be in the manual that you need to look in the changelog. ;-) -- ArjanB
:-)
Seriously, Arjan, you should write something to put in the Statements section. -- Daniel
| Topic NiceCasts . { Edit | Attach | Ref-By | Printable | Diffs | r1.24 | > | r1.23 | > | r1.22 | More } |
|
Revision r1.24 - 06 Jun 2003 - 20:26 GMT - AlexGreif Parents: WebHome |
Copyright © 1999-2003 by the contributing authors.
All material on this collaboration platform is the property of the contributing authors. Ideas, requests, problems regarding TWiki? Send feedback. |