Pair should implement Map.Entry


#1

For better or worse, Map.Entry is Java’s Pair. Kotlin Maps take Pairs as though they were Entries. Kotlin provides Map.Entry.toPair() which acknowledges that Map.Entry and Pair are at least somewhat interchangeable. But what made me think Pair is-a Map.Entry?

I had a method for adding attribute-value pairs to a URL: addAttrs(items: List<UrlAttrValue?>). List because you’re technically allowed to have multiple parameters with the same name, and if you do, their order becomes important. I made a UrlAttrValue interface and a default AttrValue data class. I think this is textbook Kotlin/Java OOP.

But the Java/Kotlin client code usually starts with a Map of key-value pairs and doesn’t care about order. I found myself forgetting the name UrlAttrValue and writing implementations of (I’d forgot there was already an AttrValue implementation). Eventually, I realized, it’s just a pair (Pair). An immutable key-value pair. If I were using this primarily from Kotlin, I would make it take a Pair, but it’s used a little more from Java, so what to do?

The best solution I could come up with was addAttrs(items: Iterable<Map.Entry<String, TaintedS?>?>). I can now pass myMap.entries in Kotlin, myMap.entrySet() in Java. But what about when there are duplicates and order is important?

I have been using a Tuple2 implements Map.Entry in Java for a few years now:

.addAttrs(vec(tup("duplicateAttr", taint("value1")),
              tup("duplicateAttr", taint("value2"))));

It made me expect that in Kotlin, I could:

.addAttrs(listOf("duplicateAttr" to taint("value1"),
                 "duplicateAttr" to taint("value2")))

I mean, I can use Tuple2 in Kotlin and it works fine. I just found that having Tuple2<A,B> (an immutable pair) implement Map.Entry<K,V> has been incredibly convenient and not led to any confusion. I’ve even gone so far as to implement SortedMap to store and return Tuple2’s (well, to alter Rich Hickey’s implementation to do that).

There could be a corner case where someone uses Pair in a way that should never be treated as a Map.Entry, but I can’t think of it. If such a case ever exists, they could make their own class for it. Or maybe even use a NOT Type.


#2

It looks like a Credential

data class Credential(val username:String, val password:String)

Should Credential implements UrlAttrValue and Map.Entry<String, String>?


#3

Yes, that was essentially my AttrValue implementation. I love the way it’s so easy and brief to create these one-off classes with meaningful names in Kotlin! Still, it seems to me this could be handled with a built-in type (Pair if it implemented Map.Entry) instead of creating my own.