Variable reassignment and raw types :-)

John Hendrikx john.hendrikx at gmail.com
Tue Apr 18 11:08:30 UTC 2023


So, I was doing raw type clean-up in some obscure graphics code, and I 
noticed I couldn't get things to compile anymore when I fixed all the 
raw types. It turns out that at some point a List (actually a Vector) 
which was using raw types was being assigned to another variable that 
also held a list, but after fixing the raw types those were actually two 
different types of lists.

The code was like this:

     public Vector calculate(Vector left, Vector right) {
         Vector edges = new Vector();

         addEdges(edges, left, AreaOp.CTAG_LEFT);
         addEdges(edges, right, AreaOp.CTAG_RIGHT);

         edges = pruneEdges(edges);

         if (false) {
             System.out.println("result: ");
             int numcurves = edges.size();
             Curve[] curvelist = (Curve[]) edges.toArray(new 
Curve[numcurves]);
             for (int i = 0; i < numcurves; i++) {
                 System.out.println("curvelist["+i+"] = "+curvelist[i]);
             }
         }
         return edges;
     }

The correct full signature of this method is supposed to be:

     public Vector<Curve> calculate(Vector<Curve> left, Vector<Curve> 
right);

In other words, Curves go in, and Curves come out.  The code starts by 
making a new Vector to hold edges (Edge class).  It converts all the 
curves to edges with the `addEdges` method. Then it calls `pruneEdges`.  
Despite the name, this method converts these edges back into curves, but 
here is where it gets confusing.  The result of this method is assigned 
to the variable edges, overwriting the existing Vector (that holds 
Edges), and now it holds Curves.  The debug code that follows shows 
things being casted to Curve, which hints at what is happening (but I 
disregarded this initially as it is debug code and might be out of 
date).  At the end edges are returned, or so you think.

To make things even more confusing, there is a bug in `pruneEdges` that 
initially made me assume it actually returns Edges; after I added the 
generic parameters this function looks like this:

     private Vector<Curve> pruneEdges(Vector<Edge> edges) {
         int numedges = edges.size();
         if (numedges < 2) {
             return edges;    // COMPILE ERROR
         }

         ... hundred more lines dealing with Curves ...

         return curves;  // actual curves!
      }

The above doesn't compile anymore because you can't return a 
Vector<Edge> as a Vector<Curve>.  The correct code here would return an 
empty vector, because when there are 0 or 1 edges, you can't make any 
curves and they won't encompass any Area (which is what the class is 
dealing with).  Likely this case is never hit in tests or real use, so 
it's not affecting anything in JavaFX.

Long story short, fixing raw type problems can not only lead to less 
casting needed, but it can also uncover real bugs :)

--John

PS. in JIRA I noticed that this code sometimes is a bit of a performance 
hog; it may help a bit to replace those Vectors for ArrayLists...



More information about the openjfx-dev mailing list