Because I do a lot of Swift, and am enjoying learn...
# announcements
t
Because I do a lot of Swift, and am enjoying learning Kotlin as well, I had found a blog post or something that made me feel I could be swift-esque with null pointer safety in Kotlin by using the pattern:
Copy code
(some.code)?.let { thing ->
  makeHayWith(thing)
} ?: run {
  mournNoThing()
}
(it follows Swift’s
if let … {} else {}
pattern nicely) But I discovered there’s a hole in this that burned us. I should have seen this and feel kind of silly since I did Smalltalk with ubiqutuous block closures for all control flow for years. The let/run pattern breaks down when you do this:
Copy code
(some.code)?.let { thing ->
  makeHayWith(thing)?.let { hay ->
    bragAboutMy(hay)
  }
} ?: run {
  mournNoThing()
}
If
makeHayWith
returns a
null
, then the return value of the original
.let
block will return
null
, which causes the
run
block to run in addition to the outer
let
block. So what you thought was a nice substitute for Swift’s
if let ... else
pattern has just been turned into a bug waiting to happen. I’m aware of the “smart pointers” described in https://kotlinlang.org/docs/reference/null-safety.html, but these don’t really appeal to me. I like something a little more intentional and universally applied. I rarely use the kotlin let pattern as an expression, almost always as a statement, so I toyed with writing my own variant that returned a distinct type (rather than the closure return type) so that I could through sugary magic do something more akin to the Swift let thing. But I’m not sure I want to stray that far from “idiomatic Kotlin” I guess my question is, is there another pattern that I’m not aware of that I should be considering using?
k
Just
if
and smartcasting is often the better solution.
6
r
For future note, use triple backticks to format blocks of code.
t
Thanks @Ruckus, I wondered how you do that on multiline. fixed.
k
.also{}
would also work but
if
is better
t
.also wouldn’t be able to replace the let, would it? It doesn’t capture the non-nil in the block/closure. Or do you mean that it would do the “smart pointer” thing?
k
Oh I didn't realise you needed the return value
m
You can use combination of
.apply
/
run
since apply returns the initial value not what the block resolves to
a
^ which is basically the same as using a combination of `also`/`let`