This gets back to the discussion about having sepa...
# language-proposals
b
This gets back to the discussion about having separate parameter labels vs names
k
There was a discussion about that?
b
I briefly mentioned it a couple months back. First argument was “what about
varargs
?” and I had no good solution so it was quickly dropped
k
Well what about them? You're talking about having different names for a parameter for the caller in the context of named arguments and for the actual variable in the function?
b
Yeah, my idea went something like this:
Copy code
fun Array<T>.insert(at index: Int) { /* ... */ }
but then they said that conflicts with
Copy code
fun Array<T>.add(vararg elements: T) { /* ... */ }
So in that case
vararg
looks like a label but should be considered a qualifier. I said we should move it to after the
:
and before the
T
, but they said something about that making types harder to distinguish… or something… It’s not very clear in my head. Someone mentioned some horrid syntax like this at some point and I gave up
Copy code
fun Array<T>.insert(@ParameterLabel("at") index: Int) { /* ... */ }
r
what about insert(at|index: Int) or other character between?
1
or just deprecate vararg and make it
add(elements: ...T)
g
what is idea behind additional label, I didn’t get it
k
Deprecate
vararg
? Kotlin is stable, you can't just deprecate commonly used core language syntax.
1
g
just to have different name of variable?
Looks like overcomplicated thing
that can be solved like:
Copy code
fun Array<T>.insert(at: Int) { 
   val index = at
   /* ... */
}
Maybe I didn’t get idea correctly
r
Deprecate
vararg
? Kotlin is stable, you can't just deprecate commonly used core language syntax.
It will work the same, no code breaks
k
What do you mean then?
g
I’m not sure that this somehow useful for real world cases why not just have
at
variable instead of
index
. Imo it’s too big change for such minor feature
b
@gildor it's wonderful for making an API with natural, expressive phrasing. Instead of something like
Connection(destination="<http://google.com|google.com>", protocol=HTTP)
, you could have
Connection(to="<http://google.com|google.com>", over=HTTP)
@rrader to me,
...T
looks like "a range of elements of type T, where the left end is open", or
LeftOpenRange<T>
g
What’s wrong to use those names now?
class Connection(to: Uri, over: Protocol)
It’s completely your preferences about naming. I prefer
protocol
than
over
, but I’m not sure how label can solve naming problem for both of us. The only difference that inside of the class you will have different name of the variable. I understand that all those things about labels came from ObjC and then from Swift, but even Swift now closer to classical naming than to ObjC (but with support of labels, yeah). I just think that such big syntax change with a lot of pitfalls about name resolution, conflict with vararg etc just don’t worth of this feature goals (different name for consumer and producer) and feature itself is very doubtful, at least I don’t see good use cases
😞 1
b
Using those as the actual argument names (
to
and
over
) makes it a worse experience for me as the API writer, at the sacrifice of making it a better experience for the API user. Maybe a syntax like this would be unambiguous?
Copy code
fun <T> ensure(that=badItem: T, vararg isNotIn=allItems: T) = !allItems.contains(badItem)


println(ensure(that = "Qux", isNotIn = "Foo", "Bar", "Baz") // true
println(ensure(that = "Bar", notIn = "Foo", "Bar", "Baz") // false
k
Is it really that bad to have the first couple of lines renaming the variables?
val target = to
1
b
Not only does that exclude the
fun foo() = bar
syntax, but IDEA issues this warning:
Copy code
Variable is an exact copy of another variable and can be inlined
This inspection reports local variables either used only in the very next return or exact copies of other variables. In both cases it's better to inline such a variable
g
You can disable warning after all. Not a big thing.
worse experience for me as the API writer
It’s destiny of API writer to provide better experience for others and have worse one for yourself 😅
b
I don't disable warnings. They're there because the compiler and IDE designers believe that certain code leads to bugs. I don't want to disable the warning to solve this use case because it's still valid in other contexts
It’s destiny of API writer to provide better experience for others and have worse one for yourself 😅
Heh... True. But it can still be better
Imagine how much nicer APIs like
sortedWith(sorter)
and
compareBy(comparator)
would look if they had explicit labels, like
sorted(with= sorter)
or
compare(by= comparator)
. Heck, maybe even
list(of= foo, bar, baz)
! (I think even nicer if we used
:
here instead of
=
but that might conflict with other planned features…) https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/sorted-with.html https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.comparisons/compare-by.html
📱 1
😱 1
g
Current syntax looks more clear for me, no ugly
=
, also easier to find in autocomplete
anyway, nothing prevents you from implementing your API like this, but yeah, you cannot force consumer to use labels. And for me as for API user it’s advantage rather than disadvantage So now you can even add alias, if you really want to use this style:
Copy code
inline fun <T> Iterable<T>.sorted(with: Comparator<in T>): List<T> {
    return sortedWith(with)
}
Honestly, I don’t see any improvements of API, and even if such feature will be available all the API will use old style. it’s more about preferred style of naming rather than real language feature.
b
I think you’re projecting the usage by your heart. Because Swift does this and 3rd-party API writers accepted it wholeheartedly. They embraced it and use it everywhere. Swift functions are clearer and more expressive with labels as part of their signature, but not necessarily the parameter names
g
Swift functions are clearer and more expressive
this is just your opinion
So again, even if this true, what is preventing you from use such alias or even design your api as I proposed above, without labels, using only param names
b
The preventing thing is, for instance, I want it to always be very clear to my API user whether
myList.add(1, 2)
will add
1
to
myList
at index
2
, or
2
to
myList
at index
1
, or add
1
and
2
to the end of
myList
. It’s not my opinion that
myList.add(1, atIndex: 2)
is more clear; that’s just a fact. Introducing more information where it’s necessary is a huge part of making things clear. Making that optional and separate from variable names makes that more expressive, encouraging API designers to use this kind of syntax instead of saying “yeah it’s possible if you use this workaround which makes you do more work in every function”. Allowing required labels = clearer APIs = better understanding by API users = fewer bugs Separating labels from variable names = easier to make more expressive APIs = more use of the aforementioned required labels = better use by API users = fewer bugs These are not just feelings I have. These are rigorously-tested facts that caused the largest and most profitable tech company in the world to make the decisions they made. Please, to understand where I’m coming from, watch this:

https://www.youtube.com/watch?v=UU2fNq35xkM

especially starting around 6 minutes in
v
@benleggiero sorry for off-topic, but could you please remove the ✔️ that says "Also send to #language-proposals"? Otherwise the sub-messages get to the channel without context, which is not ideal
k
But then only the 5 or so people in this thread get to read it, instead of everybody.
t
I'm not a fan of introducing new syntax for this which makes the language more complicated when the problem can be solved fairly easily with local variables. Your comment about the issue with
fun foo() =
syntax is valid, but imo this is a whole different problem beyond the scope of parameter labels. Instead there should be something like
where
syntax in haskell to be able to declare local variables/functions in a declarative way without having to resort to
{}
which is ugly and also prevents return type inference
b
I did that for the reason @karelpeeters stated, but as per request, they've been deleted
@tschuchort that also ignores the use case of requiring them in order to make their usage more clear. This is the same reason why IDEA, out of the box, will show parameter labels before otherwise contextless Boolean and number literals.
I’ve been playing with the approach of having the parameter name be the label you want, and then renaming it immediately inside the function. This.. is no good for documentation.
@param at
and
@param with
just… they don’t read well at all. Kotlin is, in general, a rather elegant language. I think it could use a more elegant solution to this problem