One of these days I used jatran to translate the code for a simple Swing application from Java to Scala. Jatran’s translation had a few issues (some of which have been fixed since I tried it) so there were quite a few compiler errors after it finished. I fixed them and launched the application.
It was at this point that I noticed a change in behaviour and it was not clear why it was happening. After some investigation, it turned out that it was caused by the fact that variance of arrays in Scala is different from Java combined with poor usage of method overloading.
TreePath has two constructors that do different things, but one of them takes a supertype of the other:
public TreePath(Object path)
public TreePath(Object singlePath)
Because arrays are nonvariant in Scala, it means that scalac chooses the constructor that takes an Object for the following code:
def pathToRoot: Array[TreeNode] = ... val treePath = new TreePath(pathToRoot)
On the other hand, arrays are covariant in Java so the constructor that takes an Object is chosen by javac for the equivalent Java code. One way to force scalac to choose the correct constructor is to cast the result of pathToRoot:
def pathToRoot: Array[TreeNode] = ... val treePath = new TreePath(pathToRoot.asInstanceOf[Array[AnyRef]])
It’s a subtle issue that may affect other people automatically converting Java code to Scala, so I thought I’d bring it up in case it saves them some time. :)