5 ms·
Using null is fine. You probably don‘t need Optional. Using Optional is often „clever“ (=bad) overengineering. Every NullPointerExceptipn my code ever caused w
by Traubenfuchs 5y ago
Using null is fine. You probably don‘t need Optional. Using Optional is often „clever“ (=bad) overengineering.
Every NullPointerExceptipn my code ever caused was good, because it helped find an error state that had no acceptable default non error state alternative.
- valenterry 5y agoNot sure if satire. But if not: > Every NullPointerExceptipn my code ever caused was good, because it helped find an error state that had no acceptable default non error state alternative. Yeah, and with Optional you would have found it at compile-time.
- hashmash 5y agoOnly if you never have the case where Optional is empty but you expected it not to be. How often is Optional.get or orElseThrow called blindly? How often is boilerplate code written which checks if the optional is empty and then throws "should not happen" exception or just logs a message? Once NullPointerException got "helpful" messages, I don't see that much advantage to Optional, considering that it provides less information out of the box.
- convolvatron 5y agofor me this is one of the bigger festering wounds in programming. error handling doubles the size of the code. error handling is complicated. so we put on our big-dev pants and build all sorts of structures around handling errors to make it more sound/ergonomic. but at the end of the day: o its still very difficult to respond in a semantically meaningful way to errors as code o they still almost always just get dumped into a log or ignored, or just result in a panic o even if we have managed to surface them - they still aren't really that actionable by the end user so we haven't helped the situation much, but some of these answer like catch/throw have really unpleasant consequences - we may have made it worse
- valenterry 5y agoIt's pretty much a solved problem. Just use a language that has better ergonomics for errors. Scala's ZIO is one of the better examples if you are interested to look into an alternative.
- esrauch 5y ago> Only if you never have the case where Optional is empty but you expected it not to be I kind of think that sentence is contrary to the point of Optional, and if you start from that mindset then Optionals do end up no better than nulls. Instead you enforce good hygiene where you unwrap early and pass non-Optionals for anything that you "know" is non-null. If you call a function which returns optional, and you're find yourself thinking "nah, I _know_ this is definietly non-empty" then you're incorrect; the API explicitly is telling you that it definitely can be empty.
- hashmash 5y agoThere are certainly cases where Optional is better than a "this can be null" comment, but consider the possibility that the Map interface was designed to always return Optional. If I'm using a Map that I have complete control over, that I know what's in it (I think), then I'll call Map.get(x).orElseThrow(). This isn't an improvement over a Map.get(x) call that can return null. It's also uglier, and as shown by the Rust benchmark, much slower. I'd be happier with a Map interface that had a "tryGet" and "get" pair, where only the latter threw an exception. No need for Optional.
- valenterry 5y agoIt _is_ an improvement. If you just do "Map.get(x)" and you get null because your thinking was wrong, then the NPE will pop up potentially 10 layers later or an hour later, when the null-value was tried to be used in your program. On the other hand, with "Map.get(x).orElseThrow()" you will have an exception thrown immediately! Even better, you should customize that as "Map.get(x).orElseThrow(NoSuchElementException(x))" so that you know the value that was unexpectedly not in the list. That will make debugging much easier and will potentially fail a test case while a "Map.get(x)" might not cause the test to fail.
- thinkharderdev 5y agoThe advantage is if you are explicitly modelling a value that could be empty. You can encode that into the type system by making git an Option<T> instead of just a T (that could be null). At it's most basic level it can just help reduce the possibility of NullPointerExceptions but the real benefit and reduction of boilerplate comes when you use Option as a monad. For instance, in Scala if you have a something like case class Address(street: String, city: String, state, String) case class User(id: Int, name: String, address: Option[Address]) def filterCAUsers(users: List[User]): List[User] = users.filter(_.address.exists(_.state != "CA"))
- shawnz 5y agoUsing "Optional" doesn't provide any extra compile-time guarantees except that the function could return Optional.empty(). It's already possible to see that it could return null, so there's no extra guarantees there. The only advantage of "Optional" is that it lets you deal with the empty/null case with a nice functional API instead of if statements. It doesn't do anything to solve the reverse problem of guaranteeing that non-Optional functions can't return null. If you just want to provide a hint to the caller at compile time about whether you intend for the possibility of returning null, you could use @Nullable/@NotNull annotations to achieve that with no overhead.
- ubercow13 5y agoYes, in a language like Java where it's retrofitted in years after the decision was already made to allow literally everything to be null. In other languages, that doesn't apply.
- brabel 5y agoIt doesn't apply in other languages either as long as their nulls are "safe", as in Kotlin or TypeScript.
- Zababa 5y agoThe thing is that people usually don't have a lot of code to handle the null case, so having optional where you can easily chain the happy case often offers a better experience. It also allows you to differentiate when people will return null for nothing, or when they will return an empty object. I know that in the codebase I work with, people use both. With Optional, you don't have that problem.
- shawnz 5y agoWhy not just chain the happy case by ignoring nulls, and let any potential NullPointerException bubble up to the point in the code where you would have had an "Optional.orElse" or whatever? Isn't that often just as easy? If you want it to be explicit then you could just add "@throws NullPointerException" to your javadoc. And of course having Optional in your type signature doesn't guarantee you'll never return empty objects (or even null).
- setr 5y ago> Every NullPointerExceptipn my code ever caused was good, because it helped find an error state that had no acceptable default non error state alternative. Isn’t that the point of Optional? It just moves that identification of those error states to compile-time rather than at runtime.
- xxs 5y agoMy takes is that Option is (next to) useless - the most common pattern is ...orElseNull() - yikes. The only sane approach is removing all nulls as early as they come and declaring/initializing all member variable in the c-tors.
- setr 5y agoThe problem I think is that if your dependent apis aren’t also consuming Optionals, and relying on type = null || type logic, then you end up constantly translating back and forth between the two endlessly, defeating any ergonomic gains. The ideal state is that anything that isn’t Optional is guaranteed to be non-null. So when you go ahead and remove all nulls as early as possible, you can statically guarantee that remains true forever-more. But if all your libraries just go ahead and drop this knowledge anyways, and when they return an object without meaning non-nullable, then you’re back to where you started. Whereas in an ML, I know every library is already adhering to this, so something being not-optional actually means something. Bolting it into a language ad-hoc, you go from everything can be null to this weird tristate — a type might be nullable, or might not be nullable and if it’s in an optional, it definitely is nullable… so your best bet is just checking for null every time anyways
- plmpsu 5y agoI agree. Add null checking at compile time with something like checkerframework to get the best of both worlds.
- brabel 5y agoExactly. I don't get why people complain about null-pointers in Java when all it takes to get rid of them is enabling static analysis that enforces checking for null at compile time... as that's exactly as safe as using Optional, and as Kotlin has shown, it's also possible to have a nicer interface (e.g. `something?.let { it.isNotNullHere() }`) with bare nulls... without incurring the cost of allocation or of declaring generic types everywhere. Since I started using "safe" nulls with Ceylon, nearly a decade ago, later with Kotlin and TypeScript, I've been firmly in the camp of supporting nulls in the language instead of `Optional` or `Maybe`. Rust should've used them IMO... using `?` for error propagation instead is such a weird choice.
- Zababa 5y ago? is used for Result, and not for Option. For Option, you use .unwrap(). Supporting nulls in the language also means that everything else is going to be second-class, while sum types allows you to do pretty much everything you want.
- kangalioo 5y ago(? works for both Option and Result, as does unwrap(). ? propagates to the caller, while unwrap() initiates a panic and unwinds the stack)
- khuey 5y ago? is used for Option. Just like Result, ? propagates the Err/None to your caller, and unwrap asserts that it's not present.
- deleted 5y ago[deleted]
- Zababa 5y ago> Using null is fine. You probably don‘t need Optional. Using Optional is often „clever“ (=bad) overengineering. Option types are 8 years older than null (ML: 1973, null: 1965). There's nothing clever about it. It's simple to understand, and is an explicit wrapper around an object, while a pointer is an "implicit" pointer around an object. Option<Obj> is clear, you know that it can be something or nothing. Plain Obj is deceiving. > Every NullPointerExceptipn my code ever caused was good, because it helped find an error state that had no acceptable default non error state alternative. That's the point of option types and pattern matching, it can force you to handle both cases.