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.
The pervasive lack of defensive programming slays me.
My strategy is to use Enums. And no autoboxing. And use NullObjects.
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.
#2 Optionals are syntactic sugar for null checks.
#2 is what I do. I'm not a great programmer, but keeping this sort of discipline means that my code has fewer trivial (and time-wasting) bugs.
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)
What's the representation of an optional then? Doesn't make use of some generic concept like subclasses or unions? Surely you have a generic syntax for "assume this union is this particular member" or "assume this base class is this particular subclass" or the like?
> I'm not sure that it's any more verbose or scary looking, though.
I guess the point is that I want all cast-like operations to look alike (or at least to have a way to consistently distinguish them from ordinary methods) so that I can flag them all up consistently in code reviews, linters etc.
Lints for unwrap already exist :)
Do you not have a generic syntax for unwrapping a tagged union, forcibly assuming that it's one particular component? That seems like something users would want.
(More specifically, it's a method which uses `match` internally to do this)
In practice, "add a new language feature" isn't a real solution for programmers who need to get the job done. Static type systems always have limitations. You need to be able to circumvent the type system if it isn't expressive enough for your use case.
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.
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.
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"
I'm all for strong type systems, but I also acknowledge their limitations.
(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)
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.
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.
The issue here stems from the existing community's culture, one especially full of trivially safe getters.
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.