Varargs with maps?

Is there a way to have something like Python’s **kwargs? This is the syntax I want to use:

fun makeTag(tagName: String, /* vararg props: ??? */): Elem;
makeTag("p", style = "color: red")

This is the alternative I’m using, but it doesn’t look as clean.

fun makeTag(tagName: String, vararg props: Pair<String, String>): Elem;
makeTag("p", "style" to "color: red")

I’d prefer being able to use the first syntax because it, in my opinion, appears cleaner. No attempted searches have been remotely useful, both of Google and of this forum. Would it be possible to have vararg functions defined by the second example be called like the first example?

I don’t think it’s possible. My understanding is that varargs is syntactic sugar for creating an Array, so you can only accept an Array of values.

1 Like

Like @Skater901 says, there does not seem to be anything like that right now.

However, your alternative (with using val props = _props.toMap() as the first line in method body) is actually not that bad.

Still, let’s look into the details of what is missing to get what you asked for:

I see that you ask for two things:

  1. Having a vararg-like keyword in method signature that produces a map.
  2. Having a special “named-argument”-like syntax to specify a pair.

ad 1)
The vararg keyword is bound to produce an Array. I.e. a different keyword is needed for a similar feature for maps. I.e. with some existing types K and V:

fun makeTag(tagName: String, varmap props: Map<K, V>): Elem {
    // Here, props can be used as Map<K,V>
}

which would compile to the equivalent° of:

fun makeTag(tagName: String, vararg _props: Pair<K, V>): Elem {
    val props = _props.toMap()
    // Here, props can be used as Map<K,V>
}

Two things should be considered about this:
A. What should be the name of the keyword? “varmap” is not very nice.
B. How will the key and value types be specified? Above, I wrote “Map<K, V>”, but “Map” actually is redundant, because it is clear from the keyword that it will be a map. Another possibility would be
fun makeTag(tagName: String, props: varmap <K, V>): Elem {
but that is quite inconsistent to the existing vararg syntax.

Any suggestions?

I guess with a good idea for the syntax (better than my first draft above), this could be an interesting feature for the language, if there are enough use-cases.

ad 2)
kwargs (or more precisely **) in python takes a list of named arguments.
I think that is the reason why in your proposed method call, you also used named arguments:
style = "color: red" instead of map entries (pairs).

However, named arguments are something different than a pair (at least in statically-typed languages like Kotlin).
The question is whether you really want/need this second feature additional to the varmap keyword above.
If so, please note that it would be restricted to key-type String. Then on accurate places
style = someExpression could be equivalent to "style" to someExpression.

Also, what would happen for cases like this:

fun makeTag(tagName: String = "defaultTag", varmap props: Map<String,String>) {}

makeTag(tagName = "someValue")

Is “someValue” now used for the tagName parameter or is it put into props?

But to be honest: That special syntax is quite inconsistent to the rest of the language, its use pretty restricted (only StringMaps) and the gain quite small.

Live long and prosper,
tlin47

° Actually, it is not 100% equivalent. Still the named argument of the new method accessible when calling the method needs to be “props”, not “_props”.

A. I don’t have an answer (I’m fine with varmap), but I’m also known to be terrible at names.
B. Since it is limited to strings, it could be made similar to existing varargs, only specifying the value type. Something like varmap props: V would make vararg _props: Pair<String, V>.
I do agree that the utility of this is somewhat restricted. The current to syntax works fine, if not clean. This could potentially have a use in forwarding keyword arguments, but it’d most likely only work properly for defaulted parameters or maps.