Any interest in this map literal 'hack'? Removes need for Pair (up to a point)... val myMap = mapOf( "one", 123, "two", 234, "three", 345)


#1

It is a way of not needing the Pair for a certain number of name/value pairs - maybe 10 or so name value pairs before needing to use Pair. Perhaps it could extend with vararg but it seems to me you would lose type checking?

  fun<K,V> mapOf(key1:K, value1:V) : Map<K,V> {
  return linkedMapOf(Pair(key1,value1))
  }
  fun<K,V> mapOf(key1:K, value1:V, key2:K, value2:V) : Map<K,V> {
  return linkedMapOf(Pair(key1,value1), Pair(key2,value2))
  }
  fun<K,V> mapOf(key1:K, value1:V, key2:K, value2:V, key3:K, value3:V) : Map<K,V> {
  return linkedMapOf(Pair(key1, value1), Pair(key2, value2), Pair(key3, value3))
  }
  fun<K,V> mapOf(key1:K, value1:V, key2:K, value2:V, key3:K, value3:V, key4:K, value4:V) : Map<K,V> {
  return linkedMapOf(Pair(key1, value1), Pair(key2, value2), Pair(key3, value3), Pair(key4, value4))
  }
  … maybe support up to 10 key/value pairs?
  // example 1: … removing need for Pair
  val m1a = mapOf( “one”, 345, “two”, 123, “three”, 45) // this
  val m1b = mapOf( Pair(“one”, 345), Pair(“two”, 123), Pair(“three”, 45)) // rather than this
  // example 2:
  val m2a = mapOf( “one”, Country(“NZ”,“New Zealand”), “two”, Country(“AU”,“Australia”)) // this
  val m2b = mapOf( Pair(“one”, Country(“NZ”,“New Zealand”)), Pair(“two”, Country(“AU”,“Australia”))) // rather than this

Yes, it is possibly a bit of a hack purely for aesthetic value. I have seen the approach in java land.

Cheers, Rob.


#2

Nice trick.

Not sure how practical it is though: some map literals get really long, and generating very many overloads would be impractical here…


#3

I've seen it in 3 places (Guava, Boon and one from Stephen Colourne). Generally it is limited to 5 or so key/value pairs but Stephen's version uses varargs - https://gist.github.com/jodastephen/6659515

Some might like it (up to say 5 name/value pairs which could cover a decent number of use cases) but yes it could get large/ugly as well.


#4

If it is about aesthetics, you can just use "to" infix function:

val m1b = mapOf(“one” to 345, “two” to 123, “three” to 45)


If this is about performance, we could think about inline functions of special case: iterating over varargs.
I.e. in case like this:

``

inline fun build(vararg names: String) {
  for (name in names) append(name)
}

fun test() {
  build(“a”, “b”, “c”)
}


We could just unroll the loop with actual values instead of creating array and passing it to the function. I didn’t give it enough thought if it is feasible in any complex scenario, though.
However, I believe that performance with maps of fixed content using varargs is rarely the case, and easily could be cached. It’s more like for tests, sample data, etc.


#5

> If it is about aesthetics, you can just use "to" infix function:

Ah, very nice.  Yes it is about aesthetics (just removing the need for the Pair), it is not about performance.  

Thanks, Rob.


#6

I prefer "to" since it keeps the pairs obvious.  the varargs or hack version with something such as a long list of string=>string is impossible to read.


#7

Hi Jayson,

I agree. Now that I’m aware of the infix “to” that looks like a very nice approach so personally I’m not keen on adding the suggested hack to the core api myself.

Ultimately, if someone was keen they can add this type of helper method to their own code base but I’d say it’s pretty hard to justify adding it to the core api.

Perhaps it would be good if a little code example was be in the kdoc of the mapOf() function highlighting the use of the “to” function so that style/approach was more obvious to kotlin newbies like me.

Cheers, Rob.