How about we allow Nothing as the type for varargs?
That way one can have a signature like:
fun someFun(vararg _unused: Nothing, a: Int) {
}
Which requires that a is always input as a named argument. This is helpful because it allows devs to require args that must be described by name. For reference python has a feature like this.
class InternalOnly internal constructor()
fun someFun(_unused: InternalOnly = InternalOnly, a: Int)
No need for a vararg Nothing! Note that if vararg nothing was possible, this call would still succeed: someFun(_unused = Array(), 42), while with my solution it can’t possibly happen because no one outside of your module can construct an InternalOnly value
While that certainly is a working solution. It requires the creation of the InternalOnly class everywhere one wants to do this. We already have the Nothing type which meets the needs here and would not require writing the extra InternalOnly class. Why would passing an empty array work for the Nothing type? My understanding is that that would not work.
The OP is correct, there is nothing (heh) you can pass as an argument for _unused, because everything is a super-type of Nothing and you can’t pass a super-type as an argument. There does not exist anything that is just of type Nothing.
My question for the OP: why would a dev want to require arguments that must be described by name?
If you have multiple args it is preferrable to pass them by name so one can tell which is which. If you pass them by position, one cannot tell which is which and one could reverse them accidentally. If multiple of the args have the same type and are adjacent, which positional arg is which can be confusing.
A small adaption of kyay10s answer would remove the need to create an instance on each call.
class InternalOnly internal constructor(){
companion object {
internal val instance = InternalOnly()
}
}
fun someFun(_unused: InternalOnly = InternalOnly.instance, a: Int)
Using a vararg on the other hand would require creating an array on each call just for the sake of some syntactical improvements.
If named-args-only really is a thing, Kotlin should provide a language level feature instead, that enforces this constraint on the call side. Maybe a special annotation would do the thing.
This is an opinionated comment and I hope I don’t offend you, but I’m always surprised when I see someone creates some kind of an API, a function, etc. and they don’t think in terms of: “This function provides functionality X”, but more in: “This function enforces the caller to do Y”. I think functions and APIs we create should be generally as open and flexible as possible, so the caller could use it in many different ways. Not be as restrictive and enforcing the vision of the implementer on callers.
This is like a LEGO block which has an intentional anomaly in its shape, conflicting with other blocks. Not because it was somehow needed, but because its creator didn’t want you to use the block as you like, but as they imagined it.
Maybe the only situation I think this is justified, is if we know we will need to change the order of arguments in the future and we consider this to not be a backward incompatible change. But this is a rather strange case.
Rather than doing something like this, which is rather unexpected to anyone reading the code, this should be easily doable with an annotation processor and, of course, an annotation on the method itself.
This is rather extreme, it will make any call very verbose,
And keep in mind that most of “one could reverse them accidentally.” errors should be easily caught by trivial unittests
Sure this is an opinionated statement. Writing code like this is sometime helpful in certain contexts. My context is generating classes which always store key value data originally defined in a json (schema) map. In that map certain keys have typed values. So by definition this input arg data is
unordered
values are typed
values correspond to specifically named case sensitive keys
For this use case in my opinion it makes sense to required that constructor args are passed by name only.