Reputation: 45775
I have a Scala class:
class Foo(val x:String = "default X", val y:String = "default Y" )
I want to call it from Java, but using the default parameters
Passing null
doesn't work (it assigns null
, as expected)
new Foo(null,null); //both are instantiated as null
This trick did work for me, but it's ugly, and I wonder if there is a better way:
Scala
class Foo(val x:String = "default X", val y:String = "default Y" ) {
def this(x:Object) = this()
}
Java
new Foo(null); //no matter what I pass it should work
However I would like to get rid of the constructor overload trick, and use a 0 param constructor
Is that possible?
Upvotes: 17
Views: 6304
Reputation: 1117
More generally if you have a Scala class with default args and you want to instantiate in Java overriding 0, 1 or more of the defaults without having to specify all, consider extending the Scala API to include a Builder in the companion object.
case class Foo(
a: String = "a",
b: String = "b",
c: String = "c"
)
object Foo {
class Builder {
var a: String = "a"
var b: String = "b"
var c: String = "c"
def withA(x: String) = { a = x; this }
def withB(x: String) = { b = x; this }
def withC(x: String) = { c = x; this }
def build = Foo(a, b, c)
}
}
public class App {
public static void main(String[] args) {
Foo f = new Foo.Builder()
.withA("override a")
.build();
}
}
Upvotes: 2
Reputation: 125
There is a solution, please check out section "Default Arguments" from article: https://lampwww.epfl.ch/~michelou/scala/using-scala-from-java.html
It's possible to invoke both constructors and methods by passing the appropriate positional argument from java using .$default$[number] format.
Here scope is as follows:
Example:
import za.co.absa.spline.core.SparkLineageInitializer;
SparkLineageInitializer.SparkSessionWrapper lineage = SparkLineageInitializer.SparkSessionWrapper(spark);
lineage.enableLineageTracking(lineage.enableLineageTracking$default$1());
For this example the maven dependency is: groupId: za.co.absa.spline artifactId: spline-core version: 0.3.1
Upvotes: 3
Reputation: 2969
It seems, there is no such way: https://issues.scala-lang.org/browse/SI-4278
Issue: default no-args constructor should be generated for classes with all-optional arguments
...Lukas Rytz: in respect of language uniformity we decided not to fix this one - since it's a problem of interoperability with frameworks, we think it should not be fixed at the language level.
workarounds: repeat a default, or abstract over one, or put one default int the zero-argument constructor
Then Lukas proposes the same solution as you found:
class C(a: A = aDefault, b: B = C.bDefault) {
def this() { this(b = C.bDefault) }
}
object C { def bDefault = ... }
// OR
class C(a: A = aDefault, b: B) {
def this() { this(b = bDefault) }
}
Upvotes: 7