Why is is legit to call any extension function on ...
# announcements
m
Why is is legit to call any extension function on
Nothing
, but not for example class functions? Is that a bug? This is especially confusing if
this
(unexpectedly?) resolves to
Nothing
because there’s not even a warning 😅
Copy code
error("foo").hasSurrogatePairAt(1)
d
It's legit because
Nothing
is a subtype of every other type. You can literally put a value of type
Nothing
everywhere (because such a value can never exist).
m
I know, so why doesn’t it work for class methods? It’s a subtype!
d
Probably due to how method resolution is implemented. If the Kotlin compiler would actually evaluate all instance methods of the Nothing class, it would literally have to be every method in every class. That's not really feasible.
Extension functions however are resolved like top level functions
a
Why do you want an extension to a class method 🤔 if something you can just create an extension to the class and then call that method underneath
Funny how this idea never occurred to me...an extension to a method
d
I think you are misunderstanding the issue, Anastasia
a
Maybe could you explain in detail...very curious
d
The issue is about being able to call any extension functions on a value of type
Nothing
(which is correct, because
Nothing
is a subtype of every other type so it can be the receiver for every extension function), but not instance functions (which should still technically be okay, since
Nothing
is still a subtype of every other type and so should inherit literally every instance method on every class).
a
Just tested it and it doesn't look like you can call any extension fun on Nothing🤷 the only extension function I can call on Nothing is the one I created for the type Nothing. So i can't call an extension for Unit, Boolean, Fragment or Any on Nothing
Here is the docs it doesn't actually say that Nothing is a subtype of everything https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-nothing.html
It is in Scala though 🤷 also if you open the source code in AS Nothing doesn't extend any other type vs in Scala it actually extends Any
So I am curious to know where is it said that Nothing is a subtype of any other type?
m
@Anastasia Finogenova you can call any extension function (that isn’t ambiguous) on
Nothing
, but autocompletion won’t tell you 🙂
I was editing some code where an extension function was called on an implicit
this
. After editing some other part of the code,
this
changed to
Nothing
and the extension function call was still totally fine. There wasn’t even a warning due to a Kotlin bug. So I was curious why
Nothing
behaves so differently in different situations. And I have no idea why it would be useful to call any function on
Nothing
, whether extension or not 🤔
a
Weird maybe It was a different version of the studio or kotlin plugin as when I type in the fun name it still doesn't offer me to import it but I didn't try to manually import it 🤷 it was still showing it red
m
Just use one which doesn’t need an import like
.toDouble()
a
I see, it highlights as unreasonable code but it is unreachable 😅
Why would you expect it to be reached as Nothing will never return
Nothing has a private constructor and no instance it is used as an explicit type of a function that never returns, throws an exception always for example. So the code is always unreachable
b
and why do you think it's an issue? it's ok that you can call B.extension() on A type if A extends B. And sicne Nothing extends every type, it's also ok. You won't be able to instantiate Nothing class, so it will be never invoked in runtime
a
So when does it say that Nothing extends every type in Kotlin and how is it done as it doesn't extend anything form the source code, can you point where it says that Nothing extends every type @bezrukov
m
It’s two different issues here: a) Inconsistency that you can call any extension on
Nothing
but not instance members. b) The “unreachable code” warning doesn’t always work. It didn’t for me which caused an extension function invocation on
Nothing
to not raise any flags. Simple example for b)
Copy code
fun <T> foo(block: T.() -> Unit) {}

fun main() {
    foo<Nothing> {
        hasSurrogatePairAt(1) // no warning
    }
}
a
That's interesting
When I added this.toDouble() in the body of your function it started to show the warning @Marc Knaup
So it does do it but maybe this particular case of type inference is buggy
So the issue is valid I am still curious where to read about the statement that Nothing is a subtype of everything in Kotlin docs 🤔
m
I also remember that statement but cannot find it anywhere in the documentation 😮
Runtime won’t agree though.
Copy code
enum class MyEnum

@UseExperimental(ExperimentalStdlibApi::class)
fun main() {
    println(Nothing::class.starProjectedType.isSubtypeOf(typeOf<Any?>()))    // true
    println(Nothing::class.starProjectedType.isSubtypeOf(typeOf<Unit>()))    // false
    println(Nothing::class.starProjectedType.isSubtypeOf(typeOf<MyEnum>()))  // false
}
It’s more a theoretical subtype of every type since it can be used in any place where another type is needed. But the code will obviously never execute.
b
Yes, it's not about runtime, because both java and kotlin doesn't support multiple parent classes. on JVM it's backed by Void for java compatibility, that's why you see false when trying to check on subtype. Nothing is more like just a marker for compiler.
And I also can't find an official kdoc about this 🙂
m
I just remembered a talk from KotlinConf 2018:

https://youtu.be/juFkdMv4B9s?t=1021

Maybe this helps a little bit.
👍 1
g
I don't see any inconsistency. Extension function resolution is different from instance method resolution, Nothing just doesn't have methods to call, but it's fine to call extension function or pass it as argument to any function Unreachable code warning should work, if it doesn't, it is a bug