4

I'm trying to port my application to Scala 2.10.0-M2. I'm seeing some nice improvements with better warnings from compiler. But I also got bunch of errors, all related to me mapping from Enumeration.values.

I'll give you a simple example. I'd like to have an enumeration and then pre-create bunch of objects and build a map that uses enumeration values as keys and then some matching objects as values. For example:

object Phrase extends Enumeration {
  type Phrase = Value
  val PHRASE1 = Value("My phrase 1")
  val PHRASE2 = Value("My phrase 2")
}

class Entity(text:String)

object Test {
    val myMapWithPhrases = Phrase.values.map(p => (p -> new Entity(p.toString))).toMap  
}

Now this used to work just fine on Scala 2.8 and 2.9. But 2.10.0-M2 gives me following warning:

[ERROR] common/Test.scala:21: error: diverging implicit expansion for type scala.collection.generic.CanBuildFrom[common.Phrase.ValueSet,(common.Phrase.Value, common.Entity),That]
[INFO] starting with method newCanBuildFrom in object SortedSet
[INFO]   val myMapWithPhrases = Phrase.values.map(p => (p -> new Entity(p.toString))).toMap
                                                 ^

What's causing this and how do you fix it?

vertti
  • 7,539
  • 4
  • 51
  • 81
  • I'm not getting this with the above snippet. Is this part of a larger file, and are there other definitions, imports in there? – Matthew Farwell Feb 28 '12 at 19:02
  • No, this is just an artificial example, shortest way of causing the compilation error. Normally there would be a bigger application instead of the `object Test` using the map. – vertti Feb 28 '12 at 19:08
  • 1
    I think this is a bug... well, not exactly a bug, but certainly an unintended consequence. I'd open a ticket about it. – Daniel C. Sobral Feb 29 '12 at 17:49
  • Issue filed: https://issues.scala-lang.org/browse/SI-5534 – vertti Mar 02 '12 at 07:13

2 Answers2

4

It's basically a type mismatch error. You can work around it by first converting is to a list:

scala> Phrase.values.toList.map(p => (p, new Entity(p.toString))).toMap
res15: scala.collection.immutable.Map[Phrase.Value,Entity] = Map(My phrase 1 -> Entity@d0e999, My phrase 2 -> Entity@1987acd)

For more information, see the answers to What's a “diverging implicit expansion” scalac message mean? and What is a diverging implicit expansion error?

Community
  • 1
  • 1
Matthew Farwell
  • 60,889
  • 18
  • 128
  • 171
  • 1
    Thanks for the workaround. Would be nice if someone could give the reason for the need of it too. – vertti Feb 29 '12 at 07:16
1

As you can see from your error, the ValueSet that holds the enums became a SortedSet at some point. It wants to produce a SortedSet on map, but can't sort on your Entity.

Something like this works with case class Entity:

implicit object orderingOfEntity extends Ordering[Entity] {
  def compare(e1: Entity, e2: Entity) = e1.text compare e2.text
}
som-snytt
  • 39,429
  • 2
  • 47
  • 129
  • `but can't sort on your Entity.` Why not? – Kevin Meredith Oct 20 '16 at 16:32
  • @KevinMeredith the CanBuildFrom on map requires an Ordering: http://www.scala-lang.org/api/2.12.0-RC2/scala/collection/SortedSet$.html#newCanBuildFrom[A]%28implicitord:Ordering[A]%29:scala.collection.generic.CanBuildFrom[scala.collection.SortedSet.Coll,A,scala.collection.SortedSet[A]] – som-snytt Oct 20 '16 at 16:54