Thursday, February 4, 2010

Why doesn’t toSet do what I want?

Q: Why doesn't toSet do what I want?

A: Perhaps the fault is in yourself, not in toSet.

Q: But why doesn't this compile?
List(1).toSet.map(x => ...)

A: The Scala compiler is unable to infer that x is an Int.

Q: What, is it stupid?

A: Well, List[A].toSet doesn't return an immutable.Set[A]. It returns an immutable.Set[B] for some unknown B >: A.

Q: How was I supposed to know that?

A: From the Scaladoc.

Q: But why is toSet defined that way?

A: You might be assuming immutable.Set is covariant, but it isn't. It's invariant. And the return type of toSet is in covariant
position, so the return type can't be allowed to be invariant.

Q: What do you mean, "covariant position"?

A: Let me Wikipedia that for you. See also chapter 19 of Odersky, Venners & Spoon.

Q: I understand now. But why is immutable.Set invariant?

A: Let me Stack Overflow that for you.

Q: I surrender. How do I fix my original code?

A: This works: List(1).toSet[Int].map(x => ...). So does this: List(1).toSet.map((x: Int) => ...)

(with apologies to Friedman & Felleisen. thx to paulp & ijuma for assistance)

No comments:

Post a Comment