just curious—anyone have a use case for using `Not...
# announcements
m
just curious—anyone have a use case for using
Nothing?
in your code anywhere?
z
A few times. Usually comes up as a specialization of a generic type. e.g.:
Copy code
sealed class Stuff<out T> {
  data class Something<T>(val it: T) : Stuff<T>() {
    override fun getOrNull(): T? = it
  }

  object None : Stuff<Nothing>() {
    override fun getOrNull(): Nothing? = null
  }

  abstract fun getOrNull(): T?
}
4
n
slightly OT: I've discovered that
val foo = null
does in fact compile, with type
Nothing?
:)
☝🏻 1
(not that it's useful)
m
@nanodeath I asked out of curiosity, and you’ve told me something interesting. That’s on topic in my books.
😄 2
z
I think it’s interesting that while
Unit
happens to be defined as a type with a single value (like any
object
),
Nothing?
is a type that can only have one value.
m
@Zach Klippenstein (he/him) [MOD] thanks. That actually makes a lot of sense.
s
Nothing
is a type without any values (empty set).
T?
is a type whose values are in
T
or is null.
Nothing?
has therefore one value (any value in
Nothing
- which don't exist - or null), and that value is null. Conversely, the value null has the type
Nothing?
, and
Nothing?
is a sub-type of all other types
T?
. That is why you can assign the value null to every nullable type (
T?
). 😀
✔️ 1
z
Types are fun! 😂
m
I have it—a use case for
Nothing?
that is not forced by an interface or some weird generics, but is still totally contrived. 😏 Consider this code snippet:
Copy code
when (it) {
    null -> println("It's null")
    is Int -> println("It's an int")
    is Long -> println("It's a long")
}
Maybe you think that is ugly because the first condition is not a type check like the rest of them… you can substitute
is Nothing?
for the
null
equality check.
z
Interesting as code golf, but I'd find
is Nothing?
there a lot more confusing than a simple
null
. The null makes it really clear it's a null check, using Nothing forces you to think much harder.
f
I think it's used with methods that never return, like
Copy code
while(true) {
// do work
}
Arduino coders may love this trick 😉
z
Expressions that never complete have the type
Nothing
(not nullable), because they can't ever have a value. When the compiler encounters an expression of type
Nothing
, it knows nothing after it will ever be executed, which is how it can warn about dead code after a return, for example. If something has the type
Nothing?
, it can still have a value, and code after it might still execute.
a
so
return
and
throw
are basically expressions of type
Nothing
(which is why you can put
TODO()
anywhere, and code after it is dead)
f
I think
return
and
throw
are
Unit
, but not sure here. Basically, there's a single object
Unit
but there's no object that can be of type
Nothing
s
No, Steve is correct. The
return
and
throw
are keywords forming an expression that returns
Nothing
(not even a
Unit
) and no code can follow it. Eg
return return return return return 5
is an expression that compiles fine...😀
a
.. and that’s why
val thing = findThing(id) ?: throw NotFoundException()
works
d
There is one usecase where
Nothing?
can be usefull. Assume you have some parametrized visitor
Copy code
abstract class Visitor<R, D> {
    abstract fun visitElement(
        element: Element,
        data: D
    ): R
    ...
}
and you want to have visitor which doesn't use any
data
. In this case you can parametrize
D
with
Nothing?
Copy code
class MyVisitor : Visitor<String, Nothing?>() {
    override fun visitElement(
        element: Element,
        data: Nothing?
    ): String {
        ...
    }
    ...
}

fun test(element: Element) {
    val visitor = MyVisitor()
    val result = element.accept(visitor, null)
}
Also
Unit
can be used in this case instead of
Nothing?
, but it depends of your habbits and codestyle
z
I sometimes think of it like:
Unit
means the author/API explicitly intends there to be only a single possible value.
Nothing?
means that there are probably some combination of type constraints that mean there won't be a value here, but with other type constraints there probably could be a value.