Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala default parameters and null

Tags:

scala

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.

like image 640
John Smith Avatar asked Mar 15 '12 20:03

John Smith


People also ask

What is the default value for string in Scala?

def aMethod(param: String = "asdf") = { ... } If the method is called as follows, then param is given the default value "asdf": aMethod() ...

Does Scala have null?

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.

What is the default Behaviour of Scala method?

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" .


3 Answers

Pattern matching

def aMethod(param: String = null) {     val paramOrDefault = param match {         case null => "asdf"         case s => s     } } 

Option (implicitly)

def aMethod(param: String = null) {     val paramOrDefault = Option(param).getOrElse("asdf") } 

Option (explicitly)

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.

like image 183
Tomasz Nurkiewicz Avatar answered Sep 21 '22 19:09

Tomasz Nurkiewicz


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.

like image 21
dhg Avatar answered Sep 17 '22 19:09

dhg


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:

  • The method definition clearly indicates the parameter's default value.
  • The correct default value can be picked by Scala tools, including ScalaDoc.
  • There is no need to define an additional value to substitute for the original parameter within the method body - less room for mistakes, easier to reason.
  • The pattern is fairly concise.

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.

like image 40
Vlad Gudim Avatar answered Sep 21 '22 19:09

Vlad Gudim