How do you handle undefined on dynamic value


#1

When programming in javascript the following snippet is very common:

var foo = someApi.someFoo()
if (foo) foo.bar()

When a javascript API can return all kind of values (an object, null or undefined), then this is the shortest way in javascript for checking for an actual object.

The direct translation in kotlin would be:

val foo = someApi.someFoo()
if (foo != null && foo != undefined) foo.bar

This is very cumbersome. Another pain point is that the elvis operator and the safe call operator is obviously not working for undefined.

How do you best handle undefined in kotlin?


#2
val <T> T?.nullable : T?
  get() = when(this){
    null -> null
    undefined -> null
    else -> this
  }

I do something like this for optionals.


#3

Will that work also, if the compile-time type of your nullable value is dynamic? Example:

val c: dynamic = someApi.someFoo()
c.nullable // what does this invoke?

Does this actually invoke the extension property, or does it invoke the dynamic object’s dynamic property?


#4

I’ve never checked, but it should. You invoke a property on any object and check if the instance equals null or undefined.

the first ? in my example is probably not needed.


#5

When I import the extension function and try to use it on a dynamic value, Intellij will show a warning that the import is not used. It makes somewhat sense that it would not use the statically dispatched extension since there could be a dynamically dispatched member on the dynamic type. In worst case the dynamic member would be undefined which would yield an undefined value.

I guess I will have to test your idea to see whether it works on dynamic values.


#6

My assumption was right. I made the following test:

val <T> T?.nullable : String
  get() = when(this){
    null -> "works: was null"
    undefined -> "works: was undefined"
    else -> "works: was instance"
  }

fun test() {
  console.log("test start")

  val foo1: dynamic = Foo
  val foo2: Foo = Foo
  val bar1: dynamic = Bar
  val bar2: Bar = Bar

  console.log("foo1.nullable is: ${foo1.nullable}")
  console.log("foo2.nullable is: ${foo2.nullable}")
  console.log("bar1.nullable is: ${bar1.nullable}")
  console.log("bar2.nullable is: ${bar2.nullable}")
}

object Foo
object Bar{ val nullable = "barMember" }

And it prints this to the console:

test start
foo1.nullable is: undefined
foo2.nullable is: works: was instance
bar1.nullable is: barMember
bar2.nullable is: barMember

As can be seen with foo1, the extension function is not used, when the value’s compile-time type is dynamic. The tests foo1 and bar1 together show that it will try to invoke the dynamic value’s own member (without knowing whether it exists).

Makes sense to me. But does not solve my question. How should one best deal with undefined values on dynamic types?


#7

I never really used Kotlin JS but can you declare the extension for dynamic types?

val dynamic.nullable
    get() = ...

#8

No, the compiler does not allow declaring extensions for dynamic type. Probably because it cannot be invoked (as described in my previous post).