2

I'm currently in the process of switching over from java to kotlin and one of the stated advantages that keeps popping up is that kotlin is Null safe and by default cant have variables or objects be assigned a null value but there are ways to assign a null value. However I'm not sure why this is beneficial what problems arise from Java not being null safe?

Thus far online searches have only yielded descriptions of what null safety is and not why it was implemented. Thanks in advance.

  • 4
    Are you aware of the [most frequently asked Java question](https://stackoverflow.com/questions/tagged/java?tab=Frequent) on Stack Overflow? :) – Ivar Dec 20 '21 at 13:08

2 Answers2

6

It's fundamentally a typing issue.

You might as well ask this question which is entirely analogous:

"I'm currently in the process of switching over from javascript to java and one of the stated advantages that keeps popping up is that java is typed and cant have variables or objects be assigned a value of a kind you weren't expecting. However I'm not sure why this is beneficial what problems arise from Javascript not being type safe?"

Let's say I write this method. Simple enough:

public boolean areBanksOpen(LocalDate someDate) {
  ...
}

This method checks the books about official national holidays and whatnot. In your mind you should create the notion that the author of some part of the code is different from the author of some other part of the code. Even for projects that only one person works on: Then its you, writing some code three years ago, vs. you using that code today. You don't remember (or shouldn't have to remember) every nook and cranny of that code as you wrote it back then.

Given that it's not the same person, communication is incredibly important. You need to communicate from the author of areBanksOpen to the user of that method: What is it called, what does it do, how do you use it? Yes, you can write a gigantic tutorial, of course, but communication is a little more complicated than that; if 95% of your programming hours are spent reading tutorials in webbrowsers, that's not good. A quick reminder, as well as 'training wheels' from your editor environment that detect errors you make are good things to have.

In java, the typing does that. In java, you can't write areBanksOpen("10-12-2021"). Your editor will instantly tell you this is not going to work, you have to specify a LocalDate instance, not a String. In javascript you have no idea until you run it.

nullity is the same way. There is no way for the IDE or someone perusing the javadoc to figure out that the areBanksOpen method accepts null or not. Can I call areBanksOpen(null), or not? Same for return types: Given a method String getStudentName(StudentId studentId), can null even be returned?

In that sense all types in java are really That | Null - as in, that getStudentName method returns "Either a String or null", as in, that's what the signature means, even if the docs call out: This method throws some exception if studentId isn't found, and all students have an ID (thus implying: No, this method never returns null). The method signature does not convey that information, only the docs do. Exactly analogous to how a method in javascript:

/** Pass a date object, returns a boolean whether banks are open */
function areBanksOpen(date) { .. }

in javascript explains how it works in the docs but the signature itself doesn't provide this information, which means [A] the editor can't be a second pair of eyes because editors don't read documentation but they can understand signatures, and [B] you don't get the benefit of quick lookups in auto-complete boxes and the like.

That is what the advantage is about: In kotlin you DO know, as does your editor

HOWEVER, the ones who told you this are misinformed. Java has this too, it's called nullity annotations. In java you do something like:

public boolean areBanksOpen(@NonNull LocalDate when) {}

and then IDEs will insta-redline any attempt to call areBanksOpen(null) or areBanksOpen(someVar) where simple code analysis shows that someVar might contain a null value. That's not a reason to switch to kotlin.

rzwitserloot
  • 85,357
  • 5
  • 51
  • 72
  • 8
    `@NonNull` is not at all the same as null safety. You can pass an `Integer i` parameter into a function that takes a `@NonNull Integer i`, and of course that *can* be `null`. Also `@NonNull` is not checked by the compiler and therefore is not a language feature, but a tooling feature. – flyx Dec 20 '21 at 13:35
  • @flyx You've chosen a definition of 'safety' that doesn't match the definition used here. It's "safe" in the sense that the IDE knows and generates warnings, and you know because the auto-complete dialog tells you. It's not "safe" in the sense that if you ignore the warnings or fail to configure your IDE correctly, you can still get a null in there. Kotlin, at least if being compiled to JVM code, __is no different__. I don't think it's worthwhile treating academic cases or malicious intent as 'unsafe' unless we're talking security. If you have idiots/malicious coders, you have bigger problems. – rzwitserloot Dec 20 '21 at 14:20
  • @flyx similarly, the difference between a 'language' and a 'tooling' feature is academic. The compiler __is__ a tool. You get absolutely nothing whatsoever if `kotlinc` isn't installed and you use notepad to edit a kotlin file. That's the nature of this answer: What __actually__ is the experience as you write code? In either case (use kotlin, or use java with nullity annotation awareness), the answer is: I easily know which APIs expect/generate nulls, and if I fail to account for it, my environment tells me about this during write AND compile time. Assuming I installed everything correctly. – rzwitserloot Dec 20 '21 at 14:21
  • @rzwitserloot *the difference between a 'language' and a 'tooling' feature is academic* - I disagree. While the compiler is a tool, it's the *only* thing that can produce a runnable program from your text. So in effect, there is no way you can run a program that has a nullability problem. `@NonNull` just triggers warnings in your editor, you can still very much compile broken code, and ship it. – Joffrey Dec 20 '21 at 14:51
  • As I demonstrated by example, `@NonNull` does not give you any safety. You can get `null` even when using it and getting no warnings in the IDE. Also, Kotlin only generates the same JVM code as Java [to be callable from Java](https://kotlinlang.org/docs/java-to-kotlin-interop.html#null-safety) – with other backends, e.g. Kotlin/Native, the compiler *can* omit the null-checks because by language semantics, a null value is impossible to occur. Also, private Kotlin functions *do* generate different JVM code since they do omit the null check. – flyx Dec 20 '21 at 14:52
  • _You can get null even when using it and getting no warnings in the IDE._ No you can't unless you intentionally messed up its configuration. Using tools like lombok you can have null checks injected the same way `kotlinc` does if your worry is that you have written a library and are worried somebody without an IDE configured to look at null annotations is going to use it. – rzwitserloot Dec 20 '21 at 15:25
  • _While the compiler is a tool, it's the only thing that can produce a runnable program from your text_ Yes, kotlinc is closed/unspecced. But `javac` is not. Ecj exists, for example. It's a bit bizarre to claim a language whose effective spec is 'whatever this source code repo can compile' and call that _upside_. You said it, kotlin interacts with java code and compiles to class files. Class files can be produced by many, many tools. – rzwitserloot Dec 20 '21 at 15:27
2

Without null-safety...

  1. It's easy to forget a member reference in your class might be null. If you use what you think is an object reference but it's actually null you get a NullPointerException.

  2. There's no compiler-enforced way for a method to declare it is only able to handle non-null parameters. The author can mark it with some annotation or put a note about it the documentation of the method, but null values could still be passed through and cause a NullPointerException or other Exception of the author's choosing.

  3. There's no compiler-enforced way for a method to declare it might return a null value. The author can mention it in the documentation or put some annotation on it, but if you fail to notice these or forget, you might try to use a null return value as an object reference and cause a NullPointerException.

  4. Code that once worked could stop working and start causing NullPointerExceptions if a method that used to never return null starts sometimes returning null. Since it's not enforced by the compiler, you get the exception at runtime instead of getting a compiler error so you can fix it.

Tenfour04
  • 83,111
  • 11
  • 94
  • 154