Proper usage of nullable vars after check for nullness


#1

When I have the following code:

class MyClass {

  var myvar : String? = null


  fun setMyVar(value: String) {
  myvar = value;
  }


  fun someFunc() {
  if(myvar != null) {
          otherFunc(myvar) // <-- gives an error, cannot pass String? to function which expects String
  }

  }
}


fun otherFunc(str: String) { /* do something with str */ }

So I wonder what is the idiomatic thing to do at the highlighted point?
Is it
otherFunc(myvar as String)
or
otherFunc(myvar!!)

I kinda expected Kotlin to figure out that I just did a null check, but it seems that it does this only for vals, not vars (I bet because vars are subject to concurrency issues).


#2

We will make the compiler a little smarter with vars, although mostly with local vars: class properties may turn out to be computed and give another value each time. For now you should use !!


#3

Got it, thanks!

Enjoying Kotlin very much so far!

Coming from Java it is also not very clear for my what are the best practices to structure packages.
If I got it right, Kotlin does not require 1to1 correspondence between dir structure and package names…

And in Java I used to write helper static methods and put them in namespace aka

ThemeParser.parse(filename)

in Kotlin I could just do

ThemeParser.kt:
fun parse(filename)

But then in some other file I could just write ‘parse(filename)’ after importing this function.

What bothers me a little is that this nice prefix is lost and ‘parse’ call looks just like a local one.

ThemeParser.parse() would have been much clearer to me.


#4

isn't it better to use let instead?

 
myvar?.let {
    otherFunc(it)
}

#5

From a point of view of clean OO programming you would go with ThemeParser().parse(filename) You could define a convenience class method ThemeParser.parse(filename), which calls the instance method parse(filename). But that doesn't buy you much since class instantiation is that concise in Kotlin.

As what

ThemeParser.kt:
fun parse(filename)

is concerned I would recommend only to do this when you have a good reason not to create an instance method (aka a method defined inside a class). I have problems to find a situation where this makes sense. Actually, I don’t understand why this kind of global methods can be defined in Kotlin. If you want a method to have “global scope” you could easily add it to class Object as an extension method or import it through a trait. Now people come and ask exactly that kind of question as in this thread. But I might be too narrow-minded here, being biased from the old days when developing in Smalltalk ;-).

Peace, Oliver


#6

Hello, Oliver.

I am looking not from OO perspective, but from a functional one :slight_smile:

Why create a class when I do not need one. Just for the sake of wrapping some method which is static in its nature?
Seems not right. So I’m glad that Kotlin is that concise - it allows me to just create funcitons when I do not need classes.

I like this. I just didn’t get how to structure packages yet…


#7

It's different behavior, and the choice is up to you


#8

In ye olden days before Java insisted everything had to be in a class, we'd just call the function parseTheme() and be done with it :)


#9

Yes, I am also starting to think that I just got this new java-land habit which is now hard to shake off :)


#10

I think it is a better approach to have a static method Math.abs() as in Java rather than a global function abs(). Putting mathematical methods into a class Math still creates some order where you know where to look for things. Having an ever growing number of global functions results in a big soup where you have to know tons of things by heart. In Java you know that you have to look into class Math when looking for a mathematical function. Static imports in Java solve the problem of not having to type in Math.abs() all the time.


#11

You still can use Java's Math class if targeting JVM. In "pure" Kotlin you could have 'math' package with all top level functions you need.


#12

The point we are discussing here is that having the call looking like MyMath.abs() introduces some semantic context: by just looking at this call I can say that it comes from other source file (or module). On the other hand, if I just 'import mykotlinmodule.mymath' and then have 'abs()' in code - this doesn't immediately tell the reader of the code whether this 'abs()' call is defined in current source file or not.

I agree that having MyMath.abs() is better for readability.
This could be solved by qualified imports (aka Haskell/Python etc) but IIRC Kotlin doesn’t have any


#13

You could always define the functions as part of an object to get those same semantics.


#14

Yes, but that looks more like a workaround. I would have to instantiate that object for no reason. Altough this might be some minor detail not worth discussion, I don't know.


#15

I think for something like "abs" it's pretty clear what it does without any prefix. For other more complicated functions, a longer name is probably as good as a prefix.


#16

I sometimes do this, it results in one superflous line, but I like it.

var text: String? = null


fun printText() {
  val t = text
  if (t != null) {
           … (t is now smart cast as non-null String)
     }   
}


#17

Nice trick, thank you.