I'm looking for some best practice advice. I've go...
# getting-started
v
I'm looking for some best practice advice. I've got a simple class
class Grid(val x:Int, val y: Int)
but in some cases there won't be a value. Rather than make it nullable, I'd like to be able to return something like
Grid.NONE
instead. But not sure if this is a case for sealed classes, or interfaces, or an enum... I don't want to make
Grid
open, and it's likely that
Grid
will expand with additional properties and functions over time. Any suggestions?
d
Either nullable or sealed class.
t
What bit won't have a value? as in, sometimes you can create a Grid, and sometimes you cannot?
v
If I were writing in Java, I'd definitely just have to add null checks. Maybe I'm overthinking it, it's a simple use case. For now I've gone sealed class, like this:
Copy code
sealed interface TileGrid
class Grid(val x: Int, val y: Int) : TileGrid
object NONE : TileGrid
t
There are a lot of good options, null is something different in kotlin than it is in java, since it is part of the kotlin type system. So returning null in java is a bit of an anti pattern, but in kotlin it is a good way to show the function can fail:
Copy code
fun getGrid() : Grid?

getGrid()?.let{ println(it) }
is not a bad thing to do in kotlin. So it kinda depends on the rest of your application and how you use the function result
r
You’d need a really strong reason not to use
null
to mean no value in Kotlin. Typesafe nulls transform them from a bad to a good idea. Arrow have even deprecated their
Option
class in favour of
null
. If for some reason
null
really doesn’t work, how about a
java.util.Optional
? Or use a typealias of
arrow.core.Either<Unit, T>
as suggested here: https://github.com/arrow-kt/arrow-core/issues/114#issuecomment-641211639 ?
👍 2
Particularly, the first class language support for
null
(null safe dereferencing with
?.
, null defaulting with
?:
, null aware types, including generic types) makes nullable values massively easier to work with than any other option. One thing to look out for is opportunities to use extension functions to simplify null handling: Given:
Copy code
val x: Grid? = TODO()
Copy code
fun Grid.doSomeTransform(): String = TODO()
val result: String? = x?.doSomeTransform()
is often nicer than
Copy code
fun doSomeTransform(grid: Grid): String = TODO()
val result: String? = x?.run { doSomeTransform(this) }