I have a method like this:
def aMethod(param: String = "asdf") = {
...
}
If the method is called as follows, then param is given the default value "asdf":
aMethod() ...
But what I would like, is that if the method is called with null
, then the default value would also be applied:
aMethod(null) //inside the method, I can use `param` and it has the value "asdf".
Whats the best way to do this in Scala? I can think of pattern matching or a simple if
statement.
def aMethod(param: String = "asdf") = { ... } If the method is called as follows, then param is given the default value "asdf": aMethod() ...
Null is - together with scala. Nothing - at the bottom of the Scala type hierarchy. Null is the type of the null literal. It is a subtype of every type except those of value classes.
Scala provides the ability to give parameters default values that can be used to allow a caller to omit those parameters. The parameter level has a default value so it is optional. On the last line, the argument "WARNING" overrides the default argument "INFO" .
def aMethod(param: String = null) { val paramOrDefault = param match { case null => "asdf" case s => s } }
def aMethod(param: String = null) { val paramOrDefault = Option(param).getOrElse("asdf") }
def aMethod(param: Option[String] = None) { val paramOrDefault = param getOrElse "asdf" }
The last approach is actually the most idiomatic and readable once you get use to it.
def aMethod(param: String = null) = { val p = if(param == null) "asdf" else param println(p) }
But the question must be asked: why allow null
? Would Option
be possible in your case? For this you could do:
def aMethod(param: Option[String]) = { val p = param.getOrElse("asdf") println(p) }
This makes it clear that your method expects the possibility of a "null" argument.
If the method has just one or two default parameters that can be set to null
consider this pattern:
// please note that you must specify function return type
def aMethod (x:String = "asdf"):String = if (x==null) aMethod() else {
// aMethod body ...
x
}
There are some benefits:
Furthermore, consider the following scenario:
trait ATrait {
def aMethod (x:String = "trait's default value for x"):String
}
class AClass extends ATrait {
....
}
Clearly, here we need to extend the trait, whilst preserving the original default value. Any of the patterns that involve initially setting the parameter to null
followed by a check and actual default value will break the contract established by the trait:
class AClass extends ATrait {
// wrong, breaks the expected contract
def aMethod(x: String = null):String = {
val xVal = if (x == null) "asdf" else x
...
}
}
Indeed in this scenario the only way to preserve the original value from ATrait
will be:
class AClass extends ATrait {
override def aMethod (x:String):String = if (x==null) aMethod() else {
... // x contains default value defined within ATrait
}
}
However, in the scenario when there are more than one or two default parameters that can be set to null
the pattern starts getting rather messy:
// two parameters
def aMethod (x:String = "Hello",y:String = "World"):String =
if (x==null) aMethod(y=y) else
if (y==null) aMethod(x=x) else {
// aMethod body ...
x + " " + y
}
// three parameters
def aMethod (x:String = "Hello",y:String = " ",z:String = "World"):String =
if (x==null) aMethod(y=y,z=z) else
if (y==null) aMethod(x=x,z=z) else
if (z==null) aMethod(x=x,y=y) else {
// aMethod body ...
x + y + z
}
Still when overriding an existing contract this might be the only way to honour the original default values.
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