4 ms·
Handling nulls by wrapping references in Optionals (at least if they can't be optimised away) is IMO strictly inferior to static analysis by the compiler as in
by MrBuddyCasino 4y ago
Handling nulls by wrapping references in Optionals (at least if they can't be optimised away) is IMO strictly inferior to static analysis by the compiler as in Kotlin and forcing correct error handling. Its really all you need! The problem is not nullable references, after all Optionals can contain nulls, the problem is documenting if a value can be null via the type system and correctly handling those cases.
Hoping Java will get this one day, but probably not...
- iainmerrick 4y agoI had the same thought. Kotlin and TypeScript have a good approach here. Don’t avoid using nulls at runtime, just beef up the type system so you know at compile time when they might appear. (The only wrinkle in both cases is that you might have to interact with Java/JS code that might not be null-safe.)
- MrBuddyCasino 4y agoYes, thankfully Jetbrains have gone to the trouble of solving that by considering nullability annotations and relaxing type checking when encountering platform types and failing at runtime instead. [0] [0] https://kotlinlang.org/docs/java-interop.html#null-safety-and-platform-types https://kotlinlang.org/docs/java-interop.html#null-safety-an...
- gjadi 4y agoI've never used Kotlin, but there are several systems that provide Null Analysis in Java. For example FindBugs https://findbugs.sourceforge.net/manual/annotations.html https://findbugs.sourceforge.net/manual/annotations.html Is Kotlin better because it works out of the box or are there differences in the feature set?
- cryptos 4y agoFrom my experience Kotlin's null handling works better than these external tools. Another point is that also the APIs need some support for it, to be convenient. Kotlin has methods like mapNotNull for example.
- gjadi 4y agoI agree that it's better when its built-in because the whole ecosystem uses it. Whereas in Java you may need to wrap third party code if they don't use the null analysis (or the same tool). But regarding the feature I imagine it is the same. Or are there cases where the Java Null Analysis fails?
- pjmlp 4y agoSome tools work on bytecode level, so it doesn't matter if the code is third party or not, other than naturally one cannot change it, but you wouldn't change it as well on Kotlin.
- cryptos 4y agoAt least Oracle is working on JVM stuff that could be used to introduce union types in Java. https://openjdk.org/jeps/8204937 https://openjdk.org/jeps/8204937
- MrBuddyCasino 4y agoI've never seen this posted before, but this seems incredibly important and interesting. Maybe just needs a catchy name.
- jeroenhd 4y agoIf you set up your project with the right linters and validators, you can use @Nullable and friends to get close to Kotlin's type system. The readability of `public @Nullable frobulateWidget(@NotNull frobber)` may be questionable, but at least it'll work. I believe Jetbrains has a library that adds these annotations so its IDE (and probably other tools as well) can judge the nullability of fields. In fact, IntelliJ even has a button that will make the IDE infer nullability and add annotations for an entire class or project. Combine those annotations with a linter + pipeline that marks nullability warnings as errors and you've come pretty close to Kotlin's advantages. Of course, Kotlin also has some more advanced mutability controls and other advantages that Java doesn't get for free. When it comes to simple values, null vs non-null can be solved by using primitives (long) instead of objects (Long), as primitives can never be null.
- kaba0 4y ago> `public @Nullable frobulateWidget(@NotNull frobber)` You can mark the default state. I like to mark everything as NotNull, unless specified otherwise. That way only Nullable annotations are needed at the rare occasion null is a valid value. And I believe it gives you the exact same guarantees as Kotlin, minus the syntactic sugar — nullability is one of the few things that can be statically analyzed. Most linters also know the standard library’s nullability information, so it’s quite good.
- haspok 4y agoThe problems with null are: 1. They are not composable (can't map or flatmap or fold/reduce them). 2. They can only represent one extra value, if you need more, you are back to square one (eg. you can't return an error value, only the fact that there is no value). If we make another step, one could argue that even optionals are lacking, one should model the possible domain values with sums and products in such a way that no nulls or optionals are required. Do not try this in a language with such a basic type system as Java or even Kotlin though, you will run into the limits of the type system almost immediately.
- kaba0 4y agoIn modern Java you could do this: sealed interface Option<T> permits Some<T>, None<?> {} record Some<T>(T value) implements Option<T> {} record None() implements Option<T> { static <T> None<T> none() { return new None<>(); // can also be a single instance } } The only less than ideal part is that None needs the generic type, but that can be easily circumvented by adding a generic helper method. You can add all the Monad goodies to the Option interface and you will even get exhaustive switch cases with pattern matching. The only thing Java’s type system can’t express is abstracting those Monad goodies, but it can absolutely implement them on a case-by-case basis.
- sn9 4y agoMario Fusco gave a talk showing how to implement monadic patterns in Java years ago. I never found the talk online, but here's the speaker deck: https://speakerdeck.com/mariofusco/monadic-java https://speakerdeck.com/mariofusco/monadic-java
- haspok 4y agoThank you for bringing this to my attention, my current project is on Java 11, and I'm really struggling with the restrictions around enums (the poor man's sum type :)) and interfaces... maybe I can push for Java 17 at least! The fundamental problem in Java is, however, what you stated in your last sentence: you are limited in abstraction, in most cases you have to implement the specifics.
- 4y ago
- lmm 4y ago> Handling nulls by wrapping references in Optionals (at least if they can't be optimised away) is IMO strictly inferior to static analysis by the compiler as in Kotlin and forcing correct error handling. Its really all you need! Disagree. The Kotlin way of doing it leads to really subtle bugs in generic code, because T? is usually different from T but sometimes it's not. (For example, if you write a generic cache that caches the result of f(x) in a map, it's really easy to accidentally write code that doesn't cache the result if it's null, and not notice). Also a lot of the time you don't actually want Optional, you want Either, because you want to know why the value wasn't present. Either is really limited in Kotlin.
- kaba0 4y agoThere are actually plans to tackle it in conjunction with Value types: https://news.ycombinator.com/item?id=34700346 https://news.ycombinator.com/item?id=34700346
- mrkeen 4y ago> The problem is not nullable references Disagree. If you don't PUT the nulls into the language, you don't need a brigade of PhDs to develop the static analysis to tell you whether you have nulls. I'm sick of worshipping at the altar of backward compatibility. Just because we used to choose to include nulls doesn't mean we need to keep choosing to include them.
- MrBuddyCasino 4y agoYou still need to signal the absence of a value. This is not necessarily the same thing as a monadic Return<R, E> type as in Rust, which I quite like and would prefer over exceptions. I think the Kotlin solution is very elegant, considering the restrictions of the host platform of using exceptions as error signaling mechanism.
- dgb23 4y agoYou missed the point entirely. Nulls are just part of proper unions in Kotlin (and other languages). They are just part of the type and they are explicit. Instead of having to wrap an optional value, you just annotate the type as being the union of something _or_ null. You get the same guarantees, but it actually composes openly instead of having to create a closed, specific construct that enumerates variants.
- mrkeen 4y ago> You missed the point entirely. No.