In a pure Scala environment, I could do the following if I wanted to "add" a factory method to an existing object:
object Test
object Extensions {
object RichTest {
def someFactory = new Test()
}
implicit def fromTest(t: Test.type) = RichTest
}
...
import Extensions._
val t = Test.someFactory
I would need such a functionality in combination with an existing Java class. In my concrete example, I would like to add a factory method fromLocation
to the class com.google.android.maps.GeoPoint
(and I guess every Android developer will know why this would be useful ;-) ).
However, if I try to do something like
implicit def fromGeoPoint(t: GeoPoint.type) = RichTest
I get an error stating
type mismatch; found : com.google.android.maps.GeoPoint.type (with underlying type object com.google.android.maps.GeoPoint) required: AnyRef
So I wonder if there is any way how the above approach could be implemented - or would providing an implicit conversion from Location
to GeoPoint
be the preferred way in Scala so a Location
could be used whenever a GeoPoint
is required?
As requested in the comments, a usage scenario:
// Callback you get from the GPS
override def onLocationChanged(l: Location) {
// You want to put a marker on a map, hence a GeoPoint is required
val gp: GeoPoint = GeoPoint.fromLocation(location)
val item = new OverlayItem(gp, ...)
....
}
However, keep in mind that this is just one specific example for the general problem ;-)
As of Scala version 2.9.1 it is not possible to extend Java class with a factory method.
However, there are three alternative solutions:
Personally I'd go for the third option if I used Location
-> GeoPoint
or any other conversion a lot of the time, especially in the scenario when conversion can always be done without exceptions and class interfaces don't overlap.
implicit def geoPointFromLocation(l: Location):GeoPoint = new GeoPoint...
override def onLocationChanged(l: Location) {
val gp: GeoPoint = l // let Scala compiler do the conversion for you
val item = new OverlayItem(gp, ...)
....
// or just pass the location to OverlayItem constructor directly
val item2 = new OverlayItem(l, ...)
}
Great question! Unfortunately, I don't think it is possible. Since in Java there is no way to use the static parts of an class as a value, there is no reason for the type of the static members of a Java class to extend AnyRef. And unfortunately, to make that Java object extend AnyRef you would use implicit conversion, which require the Java object to extend AnyRef...
I'd love to be proven wrong though!
Update: you can't do this in Java, and there I think the best practice is to create your own static class in which to add the factory methods. For example, consider List in Guava.
Update: here is a full example of the differences between Java and Scala (what Dario was describing).
# vim Test.java
class Test {
public static final int foo = 1;
public final int bar = 2;
}
# javac Test.java
# ls
Test.class Test.java
# javap Test
Compiled from "Test.java"
class Test {
public static final int foo;
public final int bar;
Test();
}
Compared to, with scala:
# vim Test.scala
object Test {
val foo = 1
}
class Test {
val bar = 2
}
# javac Test.scala
# ls
Test$.class Test.class Test.scala
# javap Test
public class Test implements scala.ScalaObject {
public static final int foo();
public int bar();
public Test();
}
# javap Test$
Compiled from "Test.scala"
public final class Test$ implements scala.ScalaObject {
public static final Test$ MODULE$;
public static {};
public int foo();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With