4

I'm reading the Scala Map doc, and got confused by this method signature

def zipAll[B](that: collection.Iterable[B], thisElem: A, thatElem: B): Map[(A, B)]

What does Map[(A, B)] mean? Is it the same as Map[A, B]? Thanks

Link to the doc:

http://www.scala-lang.org/api/current/scala/collection/immutable/Map.html

stackoverflower
  • 3,885
  • 10
  • 47
  • 71

1 Answers1

3

I'm reading the Scala Map doc, and got confused by this method signature

def zipAll[B](that: collection.Iterable[B], thisElem: A, thatElem: B): Map[(A, B)]

This is not the method signature. This is the "use case signature". It is a simplified signature that indicates the most common usage of the method. The real signature is:

def zipAll[B, A1 >: (K, V), That](that: GenIterable[B], thisElem: A1, thatElem: B)(implicit bf: CanBuildFrom[Map[K, V], (A1, B), That]): That

What does Map[(A, B)] mean?

(A, B) is syntactic sugar for Tuple2[A, B], i.e. a pair (aka 2-tuple) type.

Is it the same as Map[A, B]?

No, Map[Tuple2[A, B]] is not the same as Map[A, B]: the former applies the Map type constructor to a single argument (A, B) whereas the latter applies the Map type constructor to two arguments, A and B.

Note that the Map type constructor has two parameters, so the former is simply an error: you cannot apply the Map type constructor to only a single argument, you need two.

Remember that the signature you saw is only a use case, it is written by a human for humans to read, it is not verified by the type checker. As such, it can contain bugs.

Note also that there are a lot of repetitive type signatures and use cases across the entire collection hierarchy, those are generated by additional scripts. It looks like one of those scripts simply generates a wrong signature for Map.zipAll (note that the same bug exists in the other zip variants on Map, too).

A little experiment shows that zip takes the key-value pairs of the map as the first element of the result pairs and the elements from the that collection as the second element of the result pairs, and constructs a map from that, which results in a map which has the original key-value pairs as keys and the other elements as values:

Map("one" → 1, "two" → 2) zip Seq('a, 'b, 'c)
//=> Map((one, 1) -> 'a, (two, 2) -> 'b)

So, the simplified use case signature should be something like this:

def zipAll[A](that: collection.Iterable[A], thisElem: (K, V), thatElem: A): Map[(K, V), A]

It looks like the scripts get confused and substitute (K, V) for A in the signature.

Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653
  • So what do you get ? Should it just be `Map[A,B]` ? – Stephen May 26 '17 at 10:10
  • See the update. In some sense, yes, you get `Map[A, B]`, but the `A`s are the original key-value pairs of the `this` map, i.e. `type A = (K, V)`, so you get `Map[(K, V), B]` as a result. – Jörg W Mittag May 26 '17 at 10:14