Nice TWiki > Dev > NiceCasts (r1.11) TWiki webs:
Dev | Doc | Main | TWiki | Sandbox
Dev . { Changes | Index | Search | Go }
Here are some examples where I had to use cast or notNull in my project.
Daniel asked me to make this list in order to optimize the compiler.


      JOptionPane.showMessageDialog(cast(flowWindow),
         cast("Errors in flow.\nFlow byte code could not be generated.\nFlow will be saved without byte code."),
         cast("Error"),
         JOptionPane.ERROR_MESSAGE);
flowWindow extends JInternalFrame

Can you say more about the types of the methods used? Ideally, the cases should be self-contained.

The first and third arguments should not need a cast, they are Component and String as expected. The second is supposed to be an Object in Java. Nice does not make value automatically subtypes of Object. You can use the object(...) function instead of cast(...) to do that.

For this kind of issue, I think the best is to use retyping. In particular, are you aware of the NiceSwing? project? But I would like to hear that the above fix works first. -- DanielBonniot

when I leave all casts away then the following is reported by the compiler:

   [nicec] Arguments (flow4j.designer.window.flowwindow.FlowWindow, java.lang.String, java.lang.String, nice.lang.int) do not fit: 
    [nicec] nice.lang.void showMessageDialog(?java.awt.Component, ?java.lang.Object, ?java.lang.String, nice.lang.int)
Thats why I had to use the cast -- AlexGreif

This is logical for the second argument, as I said above. Does it work if you use object(...) on the second argument, and no cast? -- DanielBonniot

yes it works :)) -- AlexGreif


      Rectangle rect = this.getHandlesBoundsRect();
      int width = cast(rect.getWidth());
      int height = cast(rect.getHeight());
getters return double

You should use:

      Rectangle rect = this.getHandlesBoundsRect();
      int width = int(rect.getWidth());
      int height = int(rect.getHeight());

int(...) in Nice is equivalent to (int) ... in Java. See http://nice.sourceforge.net/manual.html#conversion


   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 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


   public class ConnectionHandle extends Handle
      implements ConnectorListener
   {
      ...
   }

   java.util.List<ConnectionHandle> connectionHandles = this.getHandles().filter(asConnectionHandle);
   ConnectionHandle connectionHandle = connectionHandles.get(connectionHandleIndex);
   ?java.util.List<ConnectorListener> connectorListeners = conn.getConnectorListeners();
   if (connectorListeners != null  &&  notNull(connectorListeners).contains(cast(connectionHandle))) {...}
In the last line I check the existence of a ConnectorListener in a List of ConnectorListeners. The local instance connectionHandle implements ConnectorListener.

The notNull should not be necessary, since Nice 0.7.8! :-) -- DanielBonniot

I compile with 0.7.8.
Without notNull the following error is reported

   [nicec] src/nice/flow4j/designer/figure/Connection.nice: line 211, column 80:
    [nicec] No possible call for contains.
    [nicec] Arguments: (?java.util.List<flow4j.designer.figure.ConnectorListener>, <t1691, U' | U' < nice.lang.Maybe> U'<t1691>)
    [nicec] Possibilities:
    [nicec] nice.lang.boolean contains(java.nio.charset.Charset, ?java.nio.charset.Charset)
    [nicec] nice.lang.boolean contains(flow4j.designer.figure.Handle this, Point)
    [nicec] nice.lang.boolean contains(flow4j.designer.figure.Figure this, Point)
    [nicec] nice.lang.boolean contains(flow4j.designer.figure.Connector this, Point)
    [nicec] nice.lang.boolean contains(java.awt.Component, ?java.awt.Point)
    [nicec] nice.lang.boolean contains(javax.accessibility.AccessibleRelationSet, ?java.lang.String)
    [nicec] nice.lang.boolean contains(javax.accessibility.AccessibleStateSet, ?javax.accessibility.AccessibleState)
    [nicec] nice.lang.boolean contains(javax.accessibility.AccessibleComponent, ?java.awt.Point)
    [nicec] nice.lang.boolean contains(java.awt.Polygon, ?java.awt.Point)
    [nicec] nice.lang.boolean contains(java.awt.Rectangle, ?java.awt.Rectangle)
    [nicec] nice.lang.boolean contains(java.awt.Rectangle, ?java.awt.Point)
    [nicec] nice.lang.boolean contains(java.awt.Shape, ?java.awt.geom.Point2D)
    [nicec] nice.lang.boolean contains(java.awt.Shape, ?java.awt.geom.Rectangle2D)
    [nicec] <Any K, Any V> nice.lang.boolean contains(java.util.Hashtable<K, V>, V)
    [nicec] <Any E> nice.lang.boolean contains(java.util.Collection<E>, E)
-- AlexGreif

If ConnectionHandle implements ConnectorListener?, then the cast should not be necessary either. What is the error message you get without the cast? -- DanielBonniot

you are right without cast, it compiles fine. -- AlexGreif

with 0.7.8 I dont need the cast but need the notNull. If I leave the notNull off then the above problem is reported.


      ?Figure figure = getFrontFlowWindowDrawArea().getDrawing().getFigureExcept(
                  mousePos, this);
      if (figure == null)   return;
      Flowlet flowlet = cast(notNull(figure));
Flowlet extends Figure

At least the notNull should not be necessary, because you tested for null above. Does it work to remove it? -- DanielBonniot

yes it compiles. -- AlexGreif

OK, so just the cast remains. 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:
Figure <- PolygonFigure
PolygonFigure <- Flowlet
PolygonFigure <- Connection
-- AlexGreif


          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()));

Do you really need notNull? Why? -- DanielBonniot

without I get:

    [nicec] src/nice/flow4j/designer/figure/Connector.nice: line 136, column 76:
    [nicec] Arguments (?java.util.List<flow4j.designer.figure.ConnectorListener>) do not fit: 
    [nicec] <Any T> java.util.Iterator<T> iterator(java.util.Collection<T>)

Is this with 0.7.8? Then it looks like a bug. Could you produce a self-contained version?

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

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

here is the selfcontained code to test. take notNull away and the compiler complains.

package test;
import java.util.*;

public class Connector {
   ?java.util.List<ConnectorListener> connectorListeners = null;

   void deleteFigure();
   deleteFigure() {
      if (connectorListeners == null)   return;
      
      for (Iterator<ConnectorListener> iter = notNull(connectorListeners).iterator(); iter.hasNext();) {
         ConnectorListener ltnr = iter.next();
      }
   }
}

interface ConnectorListener {}
-- AlexGreif

That not a bug see http://sourceforge.net/tracker/index.php?func=detail&aid=671444&group_id=12788&atid=362788 You could copy the field to a local variable. -- 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 case.

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


more to come...

-- AlexGreif - 22 Apr 2003

OK, thanks. I'll treat them progressively.

For those that are solved, if you feel that some documentation should be added (for the numeric types, I updated the User manual, so that it compares with the Java syntax). After that they can be deleted.

Some will probably need to stay, when they are a good example of a typing problem, and how to solve it. So we can keep those there.

-- DanielBonniot - 22 Apr 2003

Topic NiceCasts . { Edit | Attach | Ref-By | Printable | Diffs | r1.24 | > | r1.23 | > | r1.22 | More }
Revision r1.11 - 23 Apr 2003 - 16:13 GMT - ArjanB
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.