24 ms·
It's so sad that Java 8 had the chance to really fix the null problem, but gave us only the half-assed `java.util.Optional<T>`. Rather than implementing optiona
by driggs 4y ago
It's so sad that Java 8 had the chance to really fix the null problem, but gave us only the half-assed `java.util.Optional<T>`. Rather than implementing optional values at the language level, it's just another class tossed into the JRE.
This is perfectly legal code, where the optional wrapper itself is null:
Optional<String> getMiddleName() {
return null;
}
- sanedigital 4y agoDon't people use @NonNull everywhere now? It's been a few years since I've programmed in Java but even then I feel like that was common practice.
- tyingq 4y agoSeems common, though it only helps so much with 3rd party libraries.
- mrkeen 4y agoYes, it's always been possible to check for nulls at runtime. Personally I use notNull(..) over @NonNull since it actually fires when you expect it to (as opposed to whether your framework dispatcher interceptor trigger decided to invoke it)
- BoorishBears 4y agoDo the heuristics used for Kotlin-interop work with notNull(...)?
- lowbloodsugar 4y agoI think he means using @NonNull for compile time checking, not instrumenting it for runtime checking (though that doesn’t hurt either).
- csunbird 4y agoisn't @NonNull just a syntactic sugar for adding checkNonNull() call as first statement to the function declaration in compile time, or am I mistaken? Just like lombok, it is supposed to generate code that checks null arguments, from what I know.
- mrkeen 4y agoI tried: @Test public void foo() { bar(null); } void bar(@NonNull String param) { System.out.println(param); } All versions of that annotation let the null right through. I tried with: import lombok.NonNull; import javax.validation.constraints.NotNull; import io.micronaut.core.annotation.NonNull; import org.springframework.lang.NonNull; import reactor.util.annotation.NonNull;
- za3faran 4y agoDid you try https://github.com/uber/NullAway https://github.com/uber/NullAway?
- guelo 4y ago@Nullable/@NotNull is great when the IDE shows the warnings, basically dev time checking. There are also tools to integrate it into your builds for compile time checking.
- mrkeen 4y agoI get a little green tick in the top right of my IDE window with the following: @Test public void foo() { final Map<String, Integer> map = new HashMap<>(); map.put("present", 1); bar(map.get("missing")); } void bar(@NotNull Integer param) { System.out.println(param); } "No problems found"
- guelo 4y agoRight, that's because the system libraries don't have the annotations. That's the biggest issue with it. But it still helps a lot if you're religious about it in your own code.
- BoorishBears 4y agoIn my experience mostly people forced to use Java who are then consuming said code in Kotlin do that
- melling 4y ago“Unannotated types are considered not-nullable” Defaulting to not-nullable is a great idea. Much less boilerplate.
- krzyk 4y agoDepends on code base, at the beginning you would prefer the opposite, (not annotated are nullable).
- erik_seaberg 4y agoRather than opting into a slightly incompatible dialect for some but not all code, I would like an IDE that lets me specify what is @Nullable, and quietly inserts @NotNull everywhere else without displaying it. We can keep the boilerplate in the bytecode without rubbing our noses in it.
- joshlemer 4y agoWhich @NonNull are you referring to, Lombok's? Or javax.annotation.NonNull, or something else?
- mrkeen 4y agoIt may have been hoped for, but it was an unrealistic hope. They couldn't have fixed it while retaining backward compatibility.
- masklinn 4y ago> They couldn't have fixed it while retaining backward compatibility. Opt-ins exist. That's what .net ended up doing: by default the language uses "ubiquitous" nullability, but you can enable reference nullability support at the project or file level. If you do that, references become non-nullable, and have to be explicitly marked as nullable when applicable.
- wizofaus 4y agoThe smart thing that C# has though is automatic conversion to non-nullable references, e.g.: void foo1(Bar bar) { ... } void foo2(Bar? bar) { if (bar != null) foo1(bar); } Which wouldn't compile if you didn't have the `if` condition.
- bagels 4y agoI love this solution. Now you have two kinds of nulls.
- modeless 4y agoJust like JavaScript!
- golergka 4y agoJavascript also has Option with fp-ts, so it still leads on this front.
- britch 4y agoI disagree. The problem with Null in my opinion is that it is the default and can easily be created accidentally. There's nothing inherently wrong with an "absence of value, value" Optional.empty is not null, it's no-value
- ender341341 4y agoBut java has the worst of both worlds cause with an optional you now have 3 cases, Optional.empty, !Optional.empty, & null instead of just 2 cases. In our code base this means we have a the rule that Optional is only allowed for returns so we aren't adding 3rd cases all over the place.
- krzyk 4y agoI have never came up to a code that would pass null in place of Optional, why?
- ender341341 4y agoBecause you don't always control where the code is being called from. Other compile time typed languages (C, C++, C#, typescript, rust, kotlin) usually would let you enforce that as part of the type system, but the java compiler will silently accept null in place of optional and throw an NPE at runtime.
- pron 4y agoWhat do you mean by had a chance? That chance isn't gone. This area is under investigation, and when we have a solution we like, we'll implement it. We can't address all issues at once. Optional isn't half-assed because it was never envisioned as a general solution to the null problem. It's simply an interface that's useful in streams and other similar cases for method return values, and it does the job it was intended to do reasonably well. It's possible that a solution to nulls in the type system could have obviated the need for Optional, but I don't think that delaying lambdas and streams until such a solution was found would have been a better decision.
- deleted 4y ago[deleted]
- johannes1234321 4y agoSo then there is language-level Optional and library-level Optional?
- pron 4y agoIf that happens, there would be language level nullability types that may supersede Optional if they indeed end up solving a strictly more general problem. It's not unheard of to have more general solutions supersede older, more specific ones. For example, the newly added pattern-matching features largely obviate the need for visitors, which are a pretty common pattern in libraries; or virtual threads, which largely obviate the need for many asynchronous APIs (and there are opposite examples, such as j.u.c locks, which followed the language's locks). That's the nature of evolution: sometimes there are surviving vestiges of the past.
- jimbob45 4y agoThis area is under investigation, and when we have a solution we like, we'll implement it What's to investigate? Just copy what C# did and be done with it.
- 5e92cb50239222b 4y ago
- dehrmann 4y agoI wonder if the plan is to add syntactic sugar for Optional<T> in a future version.
- layer8 4y agoIt wouldn’t be compatible with regular nullable references.
- nigerianbrince 4y ago@NonNull Optional<@NonNull String> getMiddleName() { return null; // error }
- kaba0 4y agoOr even just setting the default to non-nullable with any static analysis checker.
- joefkelley 4y agoDo you feel that a language has to have something at the language level to prevent NPEs? In my experience, Scala does pretty well without it. I guess is your point that the language should make it impossible to write bad code, not just make it easy to write good code?
- kaba0 4y agoJust a heads up, Scala 3 actually has a compile flag that will make types exclude ‘null’ as a valid subtype, so every nullable variable will have to have type signatures like String | Null.
- lazulicurio 4y agoimo it seemed like there was this phase of "if we pretend null doesn't exist maybe it will go away" that resulted in a bunch of design issues. Beyond Optional, the other big one to me is Map.compute/Map.merge, which subtly breaks the previous interface contract for Map. As annoying as null is, I'd rather have null than have broken apis.
- Aardwolf 4y agoIsn't Object itself (and any class) already an optional at the language level? Either it's null, so has no value, or it's not null so has a value, and you can check for null-ness. What more is needed? Seems like the opposite, a guaranteed non-null value at core language level, would be novel instead...
- usrusr 4y agoRight, if only there was a language on the JVM that did that /s It's really an eye-opener when you compare kotlin and scala, with all their superficial similarities: Where kotlin simply takes the @Nonnull annotation, promotes it to a core language feature and drowns it in convenient function-scope syntactic sugar until it's actually nice to use, scala opts for Option and stacks layer upon layer of architecture trying to make Option somehow disappear. I lost half a decade holding on to plain java snobbishly dismissing kotlin as a second class scala before I finally got converted.
- deleted 4y ago[deleted]
- cheriot 4y agoScala had the same possibility, but the ecosystem of libraries used Option<T> appropriately so in practice I never thought about null. That might be harder in an older, larger ecosystem like Java...
- dheera 4y agoI'm not a Java person but isn't this just very similar to std::optional in C++? https://en.cppreference.com/w/cpp/utility/optional https://en.cppreference.com/w/cpp/utility/optional
- masklinn 4y agoNo, because in C++ bare types are not nullable. In java, reference types are nullable, Optional being a reference type, Optional<T> can be null, Empty, or have a value, whereas T can be null or have a value. Also because std::optional does essentially the opposite. It’s a more efficient _ptr rather than a safer one. Optional<T> is strictly less efficient as it implies an additional allocation.
- krzyk 4y agoOK, so when valhalla lands I assume Optional will become value type (or we will have another class for that, to avoid issues with backward compatibility)
- dheera 4y ago> Optional<T> can be null, Empty, or have a value, whereas T can be null or have a value Thanks for the explanation. Wow, this sounds like a a bit of a mess, one because of the allocation, and also because it seems there are multiple ways something can be semantically null.
- krzyk 4y agoOne can abuse everything, but should one? (and that error should be catched by any IDE or some static analysis). Optional are quite nice and we use it where appropriate, they play nice with streams which is a nice bonus.
- pharmakom 4y agoOptional is not just another class. The control flow in the compiler will check that optionals are checked.