I am wondering why this code is invalid (Conflicti...
# announcements
a
I am wondering why this code is invalid (Conflicting overloads)
c
signature is the same ⇒ conflicting overloads 🙂
a
Which signature exactly? Parameter types are different.
c
not really, they just look different, but in fact are not.
a
Could you please elaborate
v
both of those functions will compile to javas equivalent static method
hence the signature will be the same
you can easily figure these things out if you use bytecode viewer
it comes with the kotlin plugin, search
show kotlin bytecode
action
c
your lambda parameter is actually
kotlin.jvm.functions.Function1
, so this code when compiled is resulting in the same method signature in the bytecode
v
then press decompile to see java equivalent
c
@vach there's edit and <shift>+<enter> 😉
v
whats that intellij feature or something?
c
No, this is best practice how not to spam a lot of messages in Slack 🙂
a
very counter-intuitive. seems like implementation detail which forces language feature. I would expect one of the two: 1) use different signatures for function with and without receiver 2) (not too nice) allow to use function with receiver with extra parameter (when you you want it named other than this@...)
c
Sure, there are such concessions here and there sprinkled around Kotlin. They are not arbitrary though, when you're putting a custom language onto JVM and want [almost] full and seamless Java interop, you just have to compromise in a few places. That said, there is a solution for your specific situation: add
@JvmName("someOtherName")
on one of your functions.
a
OK. thank you for explanation. it was my guess from the beginning. Still some hypothetical RFunctionX would be way nicer to be produced by backend in general. And thank you for trick with
Copy code
@JvmName
c
One of the reasons compiler doesn't use this trick automagically is that for a Java client that wouldn't be obvious. So this is left at the discretion of the developer.
a
Copy code
inline fun <T> T.use(function: T.() -> Any?): T {
    this.function()
    return this
}

@JvmName("someOtherName")
inline fun <T> T.use(function: (T) -> Any?): T {
    function(this)
    return this
}
still shows conflict
m
Considering this is an inline function, I don't think it gets it's JVM counterpart, so naming shouldn't be the issue here
c
huh, interesting, this doesn't work even if you remove
inline
. I guess we're missing something.
a
And bytecode is correct (uses someOtherName)
m
Kotlin type system looks to be the culprit
c
So, basically, because
T.() -> Any?
can in fact be called both ways, Kotlin does not know what to use there, so the problem happens before compiler even gets to
@JvmName
Which on the other hand also means, you could dispense with
function2
variant altogether and just have
function1
and call it however you like 🙂
m
T.()
looks to be just syntax sugar over
(T)
d
I didn't think
function1(t)
was allowed.
c
From the screenshot of my example above I'd say
T.()
is "_parent_" of
(T)
they're not strictly equivalent, as you cannot use
function2
both ways while
function1
- you can.
e
There are equivalent in Kotlin. Functional type
T.() -> Any?
is the same as functional type
(T) -> Any?
. Both are syntactic sugar over
Funtion1<T, Any?>
👍 1
d
Is this also true for "regular" functions, as supposed to lambdas?
e
No. It is true for functional types only
Yes, you’d still get “conflicting overloads declarations” on JVM if you try to define
fun String.(): Int
and
fun (x: String): Int
in the same scope, but you can solve it with
@JvmName
d
I was mostly talking about whether
function1(t)
will work for
fun T.function1(): Any? { TODO() }
.
e
No. It does not work this way for functions.
It would not even resolve the function, let alone be able to call it. With variables of functional type it’s deferent. It resolves regardless of how you are trying to invoke it, since it resolves the corresponding value.
d
Was this done for functional types by design or was the "type safety" too much of a bother?
a
@elizarov do you remember by any chance what was logic behind such design?
k
It's a nice feature to be able to pass a
(T) -> X
to something expecting
T.() -> X
, because in the end there's no conceptual difference, it's only cosmetic.
e
Functional types are explicitly designed in such a way.