Has anyone suggested before something like this: ...
# language-proposals
m
Has anyone suggested before something like this:
if (val foobar != null) { ... }
where
foobar
is earlier declared as a nullable var. Today you can do this by writing
foobar?.let { foobar -> .... }
but I dislike this: 1. It is a conditional but looks nothing like one. The meaning isn't obvious to someone new to Kotlin even if it's logical. 2. The name of the variable is repeated twice. 3. It requires an even uglier form if you're doing a type based smart cast i.e.
(foobar as? Thing)?.let { ... }
, compare to
if (val foobar is Thing) { ... }
. This new syntactic form would combine the check with capturing current value of the variable onto the stack and shadowing the name.
👍 1
a
you can use a when statement to similar effect
Copy code
fun main() {
  var x: Number? = 1

  when (val x = x) {
    null -> println("x is null")
    is Int -> println("x is an int $x")
    is Long -> println("x is a long $x")
  }
}
Although there’s a warning for name shadowing. What might be more idiomatic is to create a new function, then
x
will be typecastable
Copy code
fun main() {
  var x: Number? = 1
  
  process(x)
}

fun process(x: Number?) {
  when (x) {
    null -> println("x is null")
    is Int -> println("x is an int $x")
    is Long -> println("x is a long $x")
  }
}
However, it would mean any code following
process(x)
wouldn’t know about the type of
x
. Maybe contracts could help?
Copy code
fun main() {
  var x: Int? = 1

  if(process(x)) {
    x.toLong() // no `?` needed - x is known not to be null
  }
}


@OptIn(ExperimentalContracts::class)
fun process(x: Number?): Boolean {
  contract { returns(true) implies (x != null) }
  when (x) {
    null -> {
      println("x is null")
      return false
    }
    is Int -> println("x is an int $x")
    is Long -> println("x is a long $x")
  }
  
  return true
}
Anyway, I agree that the scope functions are often confusing, and easy to overuse. Although, I’m glad they exist in the stdlib, because if they didn’t then every library would be implementing their own alternatives! Rather than a
?.let { ... }
I’d much rather have
Copy code
var foobar; Int? = null

val foobarValue = foobar
if (foobarValue != null) {
  // ...
}
m
Yes that's normally how I do it today because I don't like the let form either, or I write
val foobar = foobar
but then you end up with name shadowing warnings and an apparently useless statement the meaning of which is only obvious if you already know Kotlin well. And the scope outlasts the scope of the conditional, which is usually not what you need.
m
Thanks. I wouldn't have been able to find that based on the ticket title.
j
Yeah it took me a few searches! Then I remembered they mentioned Swift and that narrowed it down
a
I am not sure to fully understand. Aren't
require (foobar != null)
and
require(foobar is Thing)
enough ? As long as foobar is a val and not a var, it shiuld be autocasted in the following statements
j
That is only true if the property is in the same compilation unit
m
Yeah. The point is to more elegantly handle the case when smart casts aren't possible.