简体   繁体   中英

Return type is different when invoking the same method on different objects

I wrote the following application:

  var counters: mutable.Map[String, mutable.Map[String, Long]] = mutable.Map()
  counters("key1") = mutable.Map("counters_key"→ 20)
  counters("key2") = mutable.Map("counters_key" → 920)
  counters("key3") = mutable.Map("counters_key" → 920)
  counters("key4") = mutable.Map("counters_key" → 920)
  counters("key5") = mutable.Map("counters_key" → 920)

  var counters2: mutable.Map[String, mutable.Map[String, Long]] = mutable.Map()
  counters2("key1") = mutable.Map("counters2_key_1"→ 112000, "counters_key_2" → 1112000, "counters_key_3"→ 20)
  counters2("key2") = mutable.Map("counters2_key_4" → 9112000, "counters_key_5" → 91112000, "counters_key_6" → 920)

  val flattenedCounters =  counters.toMap.values.flatten
  val flattenedCounters2 = counters2.toMap.values.flatten

  println(flattenedCounters.getClass == flattenedCounters2.getClass) 
  //true

  println(flattenedCounters.groupBy(_._1).getClass == 
          flattenedCounters2.groupBy(_._1).getClass) 
  //false

DEMO

We are invoking the same method on the 2 objects which are of the same type. But it gives us objects of different types. Why?

The key is in the size of counters

   val map = counters.toMap
   println(map.getClass)
   //class scala.collection.immutable.HashMap$HashTrieMap
   println(map.size)
   //5

   val map2 = counters2.toMap
   println(map2.getClass)
   //class scala.collection.immutable.Map$Map2
   println(map2.size)
   //2

Looks like Scala has several implementations for Map . Map2 is optimized to hold exactly 2 elements. And there are optimized implementations up to Map4

You can find those classes in sources

When you call toMap it creates new builder that holds empty map. Then for each element adds it to the map.

  • Empty map + new key is Map1 src
  • Map1 + new key is Map2 src
  • ...
  • Map4 + new key is HashMap src

As pointed out by @Nazarii Bardiuk, it's due to the difference in the immutable Map size. Scala optimizes small Maps by storing them as single objects with elements as fields and implements larger Maps as HashMap , which uses HashTrieMap .

Here's quote under section Hash Tries from a relevant Scala doc :

Scala has a further optimization for immutable sets and maps that contain less than five elements. Sets and maps with one to four elements are stored as single objects that just contain the elements (or key/value pairs in the case of a map) as fields.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM