is there a nicer way of writing this in kotlin: ``...
# announcements
d
is there a nicer way of writing this in kotlin:
Copy code
val NullableData? = firstNullable?.let { first ->
            secondNullable?.let { second ->
                NullableData(first, second)
            }
        }
I have something like that but with many more fields so it is massively nested. I suppose I could turn nulls into exceptions and surround the whole thing in a try catch? In Haskell/Purescript/Scala we would have
do
notation for this and I think arrow had done something like this but I couldn’t find it?
j
a normal if or creating a general extension function which hides this under it but it has to have the exact number of nullables
d
yeah, I need it to be a bit more flexible than that, I’m going through some weird json constructing various data classes so this is going to come up with different data classes many times
j
you can just just fill all with !!
and later catch the exception
d
oh!
nicel
and
!!
throws a null pointer?
so I have
Copy code
fun <A> comprehend(f: () -> A): A? = try {
    f()
} catch (e: NullPointerException) {
    null
}

fun myFunction(json: ObjectNode): Pair<String, Percent>? = comprehend {
    val a = json["name"].nullString!!
    val b = json["allocated_percentage"].nullDouble?.toPercent()!!
    a to b
}
j
Not sure the exact exception, i think it can be KotlinNullPointerException
but I recommend you to check it
d
cool, I’ll check the docs
thanks for this, I’m happy with that
j
I think runCatching allows you can just not creating the comprehend function
d
just had a look, it doesn’t really help. I think I will change the name of comprehend to runNull though
n
why doesn't runCatching help?
runCatching { ... }.getOrNull()
well, I guess if you want to be sure you don't accidentally catch another kind of exception
which is fair enough
d
oh, nice
didn’t know getOrNull
runCatching { something!! }.getOrNull()
excellent thank you both for your help
🙂 2
e
Copy code
val nullableData: NullableData? =
    if (first != null && second != null) {
        NullableData(first, second)
    } else null
smart-casting
or yeah, Arrow does have a helper
Copy code
val nullableData: NullableData? = nullable {
    NullableData(first.bind(), second.bind())
}
👍 1
c
If you're searching for a
do
-notation equivalent, check out the #arrow library, they add Either and a direct equivalent to
do
(the
either
block) In Kotlin, you should not use exceptions for business logic, for many reasons, one of them is how slow they are. https://elizarov.medium.com/kotlin-and-exceptions-8062f589d07 explains when you should and shouldn't use exceptions (written by Kotlin's lead designer)
d
it’s not as simple as that, as you can see in this thread, I started without exceptions however kotlin’s nullable types do not have the tools to make my situation very readable. After some suggestions in this thread I ~ab~used exceptions in a safe and isolated way to do something very similar to
do
. The problem with arrow is that kotlin doesn’t have ad-hoc polymorphism so I can’t add the tools I need to the APIs I’m using, nullable types are “the kotlin way” and in the end @Javier and @Nir helped me achieve something similar to a Maybe monad. Just a shame you can’t generalize it over all monads in kotlin!
c
Do keep in mind the performance impact of exceptions.
d
@CLOVIS I saw
nullable
in arrow just now however that requires suspended functions. I wondered what the performance cost is of something like
runBlocking { nullable { … } }
?
performance isn’t an issue for me right now but at the same time I don’t want to throw exceptions
c
‘suspend functions' is just a fancy name for ‘nested lambdas', it's pretty much free. You can use
nullable.eager {}
(same syntax) that doesn't require the external function to suspend: https://arrow-kt.io/docs/apidocs/arrow-core/arrow.core.computations/nullable/index.html#nullable
d
ah, nice. I think I’m happy to leave it as a single
runBlocking
over all my code though, I have a lot of code scraping a load of json so there’s loads of these functions
thanks for your help!
e
If it's massively nested (more than two), then the following wins:
Copy code
val nullableData: NullableData? = run {
    val first = firstNullable ?: return@run null
    val second = secondNullable ?: return@run null
    // ... can do more, no further nesting
    NullableData(first, second)
}
d
I’m basically doing that with
nullable
and
bind()
e
Yes, but for the case of plain nullable you can do it with standard Kotlin. No need to be fancy.
d
oh I see, can you explain what
reaturn@run null
is doing?
e
d
ah, I see Ioh,
hmm, I think I prefer
nullable
although it’s nice that there is a kotlin way