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

Reply via email to