Joha
Joha

Reputation: 975

How to infer correct element type for empty invariant collection (e.g. Set)

In a case class I had to change one argument the constructor from String to Set[String]. For backwards compatibility I have now added a companion object with an overloaded apply function.

case class OldClass (x: String, y: Set[String] = Set()) {}

case class NewClass(x: Set[String], y: Set[String] = Set()) {}

object NewClass {
    def apply(x: String): NewClass = NewClass(Set(x), Set[String]())
    def apply(x: String, y: Set[String]): NewClass = NewClass(Set(x), y)
}

Now this works:

val c = NewClass("xxx", Set[String]())

But how can I make this work:

val c = NewClass("xxx", Set())

I need this, because I have some code that relies on being able to create a NewClass like this

Im getting the Error:

overloaded method value apply with alternatives (x:String) <and> (x: String,y: Set[String]) cannot be applied to (String, scala.collection.immutable.Set[Nothing])

Upvotes: 0

Views: 48

Answers (1)

Iva Kam
Iva Kam

Reputation: 962

The problem is that constructor Set() yields a value of type Set[Nothing] which is not Set[String]. To make this work precisely as you want, you can use not very reliable but working approach by adding another constructor that actually allows Set[Nothing]:

  case class NewClass(x: Set[String], y: Set[String]) {}

  object NewClass {
    def apply(x: Set[String]): NewClass = NewClass(x, Set.empty[String])
    def apply(x: String): NewClass = NewClass(Set(x), Set[String]())
    def apply(x: String, y: Set[String]): NewClass = NewClass(Set(x), y)
    def apply(x: String, y: Set[Nothing], z: Unit = ()): NewClass = NewClass(Set(x), Set.empty[String])
  }

  val c = NewClass("xxx", Set())

Note that z: Unit = () default parameter added only and only to distinguish these two constructors after generics type erasure, and default parameter y = Set.empty[String] was deleted because first constructor actually restores such syntax. I don't recommend using this approach in real code, because, well that's, a pretty counter-intuitive hack.

Upvotes: 2

Related Questions