Scala default parameters and null

前端 未结 3 2047
無奈伤痛
無奈伤痛 2020-12-24 06:09

I have a method like this:

def aMethod(param: String = \"asdf\") = {
    ...
}

If the method is called as follows, then param is given the

相关标签:
3条回答
  • 2020-12-24 07:06
    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.

    0 讨论(0)
  • 2020-12-24 07:07

    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.

    0 讨论(0)
  • 2020-12-24 07:13

    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.

    0 讨论(0)
提交回复
热议问题