People keep saying that null safety is one of the ...
# announcements
g
People keep saying that null safety is one of the important design philosophy of kotlin but I have no idea how it applies in real life code:
Copy code
/* Case A: java-style */
val result = repository.select()
if (result != null) {
    doSomething() // business logic
} else {
    doSomethingElse() // business logic
}

/* Case B: Kotlin style...? */
repository.select()?.also {
    doSomething()
} ?: run {
    doSomethingElse()
}

/* Case C: Kotlin style... + better job security through code only the creater can understand? */
try {
    repository.select()!!.run {
        doSomething()
    }
} catch (NullPointerException e) { // or whatever it was that catches not null assertion error
    doSomethingElse()
}
What is the better solution here? Obviously we can't make repository.select return non nullable type because that will result in an exception anyway. Business logic requires a different action for nonexisting row, and the only way to do this is either catch an exception, use obscure code with
.also
and
?:
, or use plain old java style code. Is there any other solution to this?
🅰️ 2
n
This is besides the point but you'd use
?.let
instead of
?.also
in your second example
g
I think
?.also
would be a better way since if we do
?.let
and then the last line inside the block returns null for whatever reason, the
?: run
block would be triggered.
?.also
guarantees that
?: run
will only be triggered when the
select
itself is null.
👍 3
f
The solution to the billion dollar mistake is that Kotlin doesn't compile if you're not handling null. It doesn't handle the business logic for you. How you format your code is up to you. Optimize for readability.
5
s
Yup, like Richard said. The fact that a type can have a null value is explicitly part of Kotlin's type system is a big advantage. This means the compiler can check for it (if you missed and if statement checking for it, etc). Fewer surprises during run time. 😀
p
Those examples kinda miss the point IMO
Copy code
fun doSomething(data: Data) = ...

// doesn't compile
val result: Data? = repository.select()
doSomething(result)

// compiles
val result: Data? = repository.select()
if (result != null) {
  doSomething(result)
} else {
  doSomethingElse()
}
s
If you want to catch the situation where there's no existing row, then return something that explicitly says there's no existing row. Using null to signify that, among other things, is a mistake.
s
No, it is not a mistake, necessarily. It depends on your domain model. If your domain doesn't care about why there is no row returned by a function, a nullable return value could be perfect for that (in lieu of an Optional). If you care about the error, a Try/Result/Either type is a good choice. In other words, it depends 😀
1
f
Null is the correct thing and definitely not a mistake.