7 ms·
Having the get() method makes the entire purpose of Optional useless. All it does is make your null-checking code even more verbose. If you need to extract the
by nv-vn 11y ago
Having the get() method makes the entire purpose of Optional useless. All it does is make your null-checking code even more verbose. If you need to extract the value, the orElse method should be suitable on all cases. Deprecating get() should be an instant decision, since other than backwards compatibility it has nothing to add to the Optional class. Including it in the first place was as much of a mistake as the null pointer.
- noamsml 11y agoI disagree. I'd rather getWhenPresent than orElse if the code has nothing to do with a missing value. If someone needs the value and uses orElse without isPresent, their code will break in new and unexpected ways rather than in the obvious one. (An even better solution is SWIFT's approach to nullable types, but that boat has sailed; intellij etc could however implement a static checker for bare Optional-getting)
- redcodenl 11y agoHow does orElse() cause new problems and/or break code? It is the same as get but forces you to think about the not available option...? I think the options orElse/orElseGet and orElseThrow are enough to replace every get() method, and they'll force you to think about the missing scenario. If you want to do something in case it is present, use ifPresent(lambda). In case you want to return something, use orElse/orElseGet or orElseThrow, or just return the Optional itself.
- masklinn 11y ago> I think the options orElse/orElseGet and orElseThrow are enough to replace every get() method, and they'll force you to think about the missing scenario. orElseThrow doesn't force you to think about the missing scenario, only to think about which exception you want to throw, which in many case you don't care for. If orElseThrow had an override throwing NoSuchElementException by default it would be a perfect replacement, alas it does not.
- redcodenl 11y agoOf course it does, you actively choose to throw something! That is, in some cases, perfectly acceptable. All three methods tell you there is something else in case you don't have a value in the optional. get() doesn't.
- masklinn 11y ago> Having the get() method makes the entire purpose of Optional useless. It doesn't quite, though it is way too short and convenient. > If you need to extract the value, the orElse method should be suitable on all cases. orElse is incorrect if you have specific expectations. get is an assertion, and used in that manner it's perfectly sensible and orElse is not. Plus orElse can send the wrong signal. > Including it in the first place was as much of a mistake as the null pointer. The only language I know which has optionals and doesn't have something equivalent to .get() is Elm, and even there you can trivially pattern-match and call Debug.crash in the Nothing case.
- weego 11y agoYou should never have concrete expectations or make assertions on an unknown, that's the entire point of any implementation of Option. Option.get leads to false confidence. I've had many arguments over use .get (in Scala) where another developers argument is "we check that it's defined higher up in the code". At that point a harmless looking refactor by someone else can introduce NPEs.
- masklinn 11y ago> You should never have concrete expectations or make assertions on an unknown As long as Optional#isPresent exists, you can have "concrete expectations" of an optional's content (or lack thereof). > At that point a harmless looking refactor by someone else can introduce NPEs. The fundamental problem is not .get, it's that you're qualifying code changes involving partial function as "harmless-looking" and "refactoring"
- pcwalton 11y agoOption.get is important. It lets you work around the type system in cases where the type system wasn't expressive enough. Given that all type systems are imprecise, this functionality is essential. I'm all for strong type systems, but I also acknowledge their limitations.
- gozur88 11y agoIf someone has managed to bork the code with a harmless looking refactor, an NPE is what you want. The code is no longer working as designed and needs to be fixed.
- neverminder 11y agoJava Optional was inspired by Scala Option was it not? And I haven't seen anyone complain about Scala Option having exactly the same get() method for ages.
- rco8786 11y agoI think it has to do with the mindset of people working with Java vs Scala. Specifically, Scala folks are taught to reach for functional concepts(map, flatMap, etc) first whereas these concepts are still new to Java land.
- haimez 11y agoIt does, but the scala community is very familiar with the functional ("lambda") approach of leaving values in an optional context while transforming it. The issue here stems from the existing community's culture, one especially full of trivially safe getters.
- neverminder 11y agoWell, maybe they need to learn the lesson the hard way, because when they start doing `foo.getBar().map(this::toString).orElse("Bar not found");` they will realize (hopefully) that this looks much more like Scala than classic Java.
- eloisant 11y agoI believe less Scala developers do "IDE-driven-development", where they just briefly look at the auto-complete to find a methods that vaguely appears to do what they want.
- lmm 11y agoThe ScalaZ folks use their own Maybe type instead so as not to have a get() method. Wartremover makes Option#get() a compile failure. Where I work "Option#get" is an automatic failure in codereview. For political reasons I doubt it will ever be removed in the Scala standard library, but there is certainly a substantial contingent that objects to it.
- winstonewert 11y agoThere is a big difference between null and .get() With null, the actual error can show up somewhere completely different in your code making it hard to trace where the null value came from. With .get() the errors happens at exactly the point where I told the compiler: "trust me, this isn't empty!" but was wrong.
- specialist 11y ago"making it hard to trace where the null value came from" The pervasive lack of defensive programming slays me.
- lmm 11y agoDefensive programming in the form of checking all parameters and all return values from library methods for null? Sure, good idea. But then you need a way to distinguish between things that should never be null and things that genuinely might not be present. So Optional is one of the pieces you need to enable this kind of style.
- specialist 11y ago"distinguish between things that should never be null and ... might not be present" My strategy is to use Enums. And no autoboxing. And use NullObjects.
- lmm 11y agoEnums don't have (dynamic) data members, do they? Sometimes you want a representation of e.g. "user's email address, or nothing if they haven't set one". More, you want that often enough that it's worth having a single generic way to represent it rather than having to construct a custom NullObject for each case.
- kazagistar 11y agoThe traditional options are Java are: 1. Assume parameters aren't null, and then everything breaks and you fix it. 2. Assume ANY object can be null, and check them all, in every single method, and create correct handling in each case. Basically no one does this. 3. Try to figure out which things can be null or not depending on context. Sometimes you are still wrong, and get NPEs. This is what people actually do. By defensive programming, do you mean #2? Because that kinda sucks compared to just using Optionals.
- steveklabnik 11y agoSometimes, you _know_ that something will be valid. Rust has an unwrap method that does the same as get does, and legitimate uses of it come in cases like this: use std::net::Ipv4Addr; fn main() { let addr: Ipv4Addr = "0.0.0.0".parse().unwrap(); } Here, I _know_ that the call to `parse()` will always succeed. More verbose handling isn't helpful. (We almost changed unwrap to assert to make it even more clear, but not everyone agreed that it was more clear)
- lmm 11y agoSounds like you want IP address literals (or more generally custom literals). If it's safe because everything's static, then, uh, make it static.
- steveklabnik 11y agoIn this specific case, sure. But it's not really about this specific case; it's about the general idea of "I know that this won't fail, even though you, the compiler, do not." Unless you have full-on dependent types, (and even then), there's going to be times where that's true; it's the nature of type systems. They have to be conservative, there will always be valid programs that are not expressible.
- lmm 11y agoI feel like that's just a special case of casting and so should be handled by casting. You can always cast Optional to Some, can't you? It's verbose and dangerous-looking but it should be verbose and dangerous-looking in my book.
- steveklabnik 11y agoIt depends on the language. In a language like Rust, direct casts mean "reinterpret these bits", and the two are represented differently, so that wouldn't work. In a less low-level language, then sure, maybe a cast would work for this case. I'm not sure that it's any more verbose or scary looking, though.
- hughw 11y agoa) he doesn't propose to deprecate the semantics of get(), just change the name. b) get() is useful and less verbose for cases where other logic has proven that the get() will succeed. boolean allPresent = a.isPresent() && b.isPresent() if (allPresent){ doSomething(a.get()) } edit: just noticed this example is the same idea merb posted earlier.