My goal is to enhance inside scala code an existing Java class using a trait mix-in. For example to add a method like java.awt.Rectangle.translate(dx, dy) to java.awt.geom.Ellipse2D class. For this I create the following trait:
trait RectangleLike {
var x: Double // abstract vals to correspond to java class fields
var y: Double // I need these vars to refer to them inside translate method
def translate(dx: Double, dy: Double) {
x = x + dx
y = y + dy
}
// more concrete trait methods here
} // defines without errors in scala REPL
Then use the trait when constructing an Ellipse:
val egg = new java.awt.geom.Ellipse2D.Double(5, 10, 20, 30) with RectangleLike
However when I execute the above script in scala REPL I get the following output:
<console>:8: error: overriding variable x in trait RectangleLike of type Double;
variable x in class Double of type Double has incompatible type;
other members with override errors are: y
val egg = new java.awt.geom.Ellipse2D.Double(5, 10, 20, 30) with RectangleLike
I suspect that this error is due to the way Scala implements vars – as a private field and a getter/setter pair of methods. Is what I try to achieve doable? Is there another way to define the java class fields in the trait and then refer to them inside the concrete trait methods?
Thanks in advance
Jack Dimas
Yes, it is doable but instead of trying to access the private fields of the classes you want to mix in with (which is most likely a bad idea anyway), you would want to declare the self-type of
RectangleLiketo bejava.awt.geom.RectangularShapeso that you can use your trait with e.g.Ellipse2D.Doublejust as well as withRectangle2D.Double.Here is how it works:
By saying
self: java.awt.geom.RectangularShape =>you declare the self-type of your trait which enables you to access all corresponding methods like the necessary getters and setters, allows for using your trait with all descendants ofRectangularShape, and also “restricts” your trait so that it can only be used as a mixin to classes which themselves are subtypes ofRectangularShape.The alternative to the above scenario is using a so-called view of your
RectangularShapewhich is a common paradigm as well. For this, you would e.g. declare a classScala has a way of implicitly viewing an object of one type as an object of another type. If you happen to call a method on a object which is not declared in its corresponding type, the compiler trys to find a type that provides this method and in particular also trys to find an implicit conversion so that your original object can be viewed as an instance of the latter type. For this to work, you would typically declare the companion object of
RichRectangularShapeas something like this:Then: