How can I define a fun with default argument value AND a vararg argument?


#1

It seems they both need to be at the end of the argument list to work

Here is what I want :

public fun bootstrap(host: String = "localhost", port: Int = 8080, vararg handlers: ChannelHandler) { ... /* netty code */ }

But when I call it without host and port, it won’t compile

So I tried to write a workaround, here is what I thought next ( a higher order fun which returns a fun )

public fun bootstrap(host: String = "localhost", port: Int = 8080) : (vararg ChannelHandler) -> Unit {   return { (vararg handlers: ChannelHandler) -> {   ... /* netty code */   } }

then I could call it this way

bootstrap("localhost")(TimeDecoder(), TimeClientHander())

But the compiler complains about Type Mismatch:

Type mismatch: inferred type is (jet.Array<org.jboss.netty.channel.ChannelHandler>) -> Unit but (org.jboss.netty.channel.ChannelHandler) -> Unit was expected

I conclude it didn't catch `vararg` in the return type specification

if I write

public fun bootstrap(host: String = "localhost", port: Int = 8080) : (jet.Array<ChennelHandler>) -> Unit { ... }

it could compile, but then I can not call it with vararg, only a jet.Array<ChannelHandler>

So my question here is, does kotlin support returning vararg fun? Or did I made a mistake?

There is another possible solution came to my mind:  We must put default arg values or vararg args at the end because otherwise it will lead to syntax ambiguity, and no more problems. So can we change the function definition syntax a little so that this kind of ambiguity is avoided?

Solution #1:  introduce segmentation to argument list, e.g.:

public fun bootstrap(host: String = "localhost", port: Int = 8080; vararg ChannelHandler) { ... }

The semicolon before `vararg ChannelHandler` is a segmentation separator, it tells the compiler there are two parts of argment list, each with the same old argument list rules.

And we call it with

bootstrap("localhost"; TimeDecoder(), TimeClientChannel())

Then the ambiguity is cleared.

Here the semicolon must be provided by calling code if there would be ambiguity, otherwise it could be called like normal fun

bootstrap("localhost", 8080, TimeDecoder(), TimeClientChannel()) // No ambiguity

If semicolon leads to confusion because people were used to for (;;) syntax, we can choose something else, like ~, but I think semicolon looks best here.

Solution #2, have multiple argument lists, e.g.:

public fun bootstrap(host: String = "localhost", port: Int = 8080)(vararg ChannelHandler) { ... }

then we still call it this way

bootstrap("localhost")(TimeDecoder(), TimeClientChannel())

But this time the compile has to decide it's a call to mulitple arg list, instead of a chained function call.

And from the syntax of function with a last fun type agument, I guess that this is not what the team wanted.

So I’d suggest solution  #1, because it seems easy to implement and does not affect the other language syntax. Is it practical?


#2

Sorry for a delayed answer. This seems to be a bug. Feel free to report it in the tracker