Search code examples
scalaintellij-ideadefault-valueinvariance

IntelliJ IDEA: default parameter values in Scala


In Scala REPL I can use Seq[String]() as a default value for a parameter of type Seq[T].

Welcome to Scala version 2.11.7 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_101).
Type in expressions to have them evaluated.
Type :help for more information.

scala> def d[T](foo: Seq[T] = Seq[String]()) = 12
d: [T](foo: Seq[T])Int

scala> d()
res0: Int = 12

Trying the same in IDEA, it complains “Seq[String] doesn't conform to expected type Seq[T]”. Why?

Screenshot of IDEA complaining about a type problem for parameter default values

  • IntelliJ IDEA 2016.2.4
  • Scala Plugin 2016.2.1
  • Scala 2.11.7

Note 1: Sorry, I know that my example function does not make much sense. However, my real (and useful) function is unnecessarily complex to post it here.

Note 2: At first, instead of type T my type name in the example was Any which was not a good idea (because it shadowed scala.Any) and caused some confusion. Thus I fixed that.


Solution

  • When you say def d[Any], the Any here is a generic place holder. It does not point to class Any in scala. It basically shadows the Any class defined globally in scala. So, when you assign Seq[String] to Seq[Any], the compiler does not know any relation between String and Any. Note that Any could be replaced with any character / word as generic place holder. The result would be the same.

    Now coming, to why this works in REPL, I am not exactly sure why REPL accepts if Seq[String] when given as a default value, but I was able to reproduce the error in repl when I do the same operation inside the method body.

    The following code in REPL throws error:

    def d[Any](foo: Seq[Any]) = {
      val a: Seq[Any] = Seq[String]()
    }
    <console>:12: error: type mismatch;
    found   : Seq[String]
    required: Seq[Any]
           val a: Seq[Any] = Seq[String]()
                                        ^
    

    I am not sure why REPL was not able to catch the error while given as a default argument.

    One alternative theory is, in general when you use generics, the value of the type will be determined based on the caller. For example,

    def d[A](a:A) = {}
    d(1) // Type of A is Int
    d("a") // Type of A is String
    

    So, when you give default value, it assigns the value of String to Any. hence the compilation success.Intellij's Type Checker works based on the first theory and shows an error. But strangely as someone pointed out earlier, the compilation succeeds.