Optionals VS Throwing Functions

Optionals vs Throwing functions

Performance

The two approaches should have comparable performance. Under the hood they are both doing very similar things: returning a value with a flag that is checked, and only if the flag shows the result is valid, proceeding. With optionals, that flag is the enum (.None vs .Some), with throws that flag is an implicit one that triggers the jump to the catch block.

It's worth noting your two functions don't do the same thing (one returns nil if no key matches, the other throws if the first key doesn’t match).

If performance is critical, then you can write this to run much faster by eliminating the unnecessary key-subscript lookup like so:

func lookUp<T:Equatable>(key:T , dictionary:[T:T]) -> T?  {
for (k,v) in dictionary where k == key {
return v
}
return nil
}

and

func lookUpThrows<T:Equatable>(key:T , dictionary:[T:T]) throws -> T  {
for (k,v) in dic where k == key {
return v
}
throw lookUpErrors.noSuchKeyInDictionary
}

If you benchmark both of these with valid values in a tight loop, they perform identically. If you benchmark them with invalid values, the optional version performs about twice the speed, so presumably actually throwing has a small bit of overhead. But probably not anything noticeable unless you really are calling this function in a very tight loop and anticipating a lot of failures.

Which is safer?

They're both identically safe. In neither case can you call the function and then accidentally use an invalid result. The compiler forces you to either unwrap the optional, or catch the error.

In both cases, you can bypass the safety checks:

// force-unwrap the optional
let name = lookUp( "JO", dictionary: dict)!
// force-ignore the throw
let name = try! lookUpThrows("JO" , dic:dict)

It really comes down to which style of forcing the caller to handle possible failure is preferable.

Which function is recommended?

While this is more subjective, I think the answer’s pretty clear. You should use the optional one and not the throwing one.

For language style guidance, we need only look at the standard library. Dictionary already has a key-based lookup (which this function duplicates), and it returns an optional.

The big reason optional is a better choice is that in this function, there is only one thing that can go wrong. When nil is returned, it is for one reason only and that is that the key is not present in the dictionary. There is no circumstance where the function needs to indicate which reason of several that it threw, and the reason nil is returned should be completely obvious to the caller.

If on the other hand there were multiple reasons, and maybe the function needs to return an explanation (for example, a function that does a network call, that might fail because of network failure, or because of corrupt data), then an error classifying the failure and maybe including some error text would be a better choice.

The other reason optional is better in this case is that failure might even be expected/common. Errors are more for unusual/unexpected failures. The benefit of returning an optional is it’s very easy to use other optional features to handle it - for example optional chaining (lookUp("JO", dic:dict)?.uppercaseString) or defaulting using nil-coalescing (lookUp("JO", dic:dict) ?? "Team not found"). By contrast, try/catch is a bit of a pain to set up and use, unless the caller really wants "exceptional" error handling i.e. is going to do a bunch of stuff, some of which can fail, but wants to collect that failure handling down at the bottom.

Optional vs throwing an exception

The example you present is not an appropriate usage of Optional. An empty Optional represents a value that is absent for a reason which could not be predicted by the caller. It is the result of a legal invocation of a method.

The code you present as the "old idiom" performs validation of the input and throws an unchecked exception if the input was invalid. This behavior should remain unchanged even if you introduce Optional. The only difference would be that the return value of Object get(i) is possibly null whereas the return value of Optional<?> get(i) is never null because there is a special state of the Optional instance representing the absence of a value.

The advantage of methods which return Optional instead of a nullable value is the elimination of boilerplate code which must make a routine null-check before trying to do anything with the returned value. There are many more advantages to using Optional purely within a method. For example:

static Optional<Type> componentType(Type type) {
return Optional.of(type)
.filter(t -> t instanceof ParameterizedType)
.map(t -> (ParameterizedType) t)
.filter(t -> t.getActualTypeArguments().length == 1)
.filter(t -> Optional.of(t.getRawType())
.filter(rt -> rt instanceof Class)
.map(rt -> (Class<?>) rt)
.filter(Stream.class::isAssignableFrom)
.isPresent())
.map(t -> t.getActualTypeArguments()[0]);

Here an important benefit is perfect scope control: the same name t is reused in each new scope for a variable of a type appropriate to that stage of processing. So, instead of being forced to have variables in scope after their useful life has expired, and to invent a new name for each following variable, with this idiom we have the precise minimum that we need to proceed.

Just for interest, you can implement equals entirely in terms of Optional:

@Override public boolean equals(Object obj) {
return Optional.ofNullable(obj)
.filter(that -> that instanceof Test)
.map(that -> (Test)that)
.filter(that -> Objects.equals(this.s1, that.s1))
.filter(that -> Objects.equals(this.s2, that.s2))
.isPresent();
}

Although I find this idiom very clean and readable, it is not currently optimized enough to be recommended as a production-worthy choice. Future versions of Java may make this viable, though.

How can I return an optional instead of throwing an exception?

"Instead of adding a throws statement to my method or fitting it in a try and catch block"

Well, those are your two options. Either you can

  • Catch the exception yourself and return an empty Optional. This is not a good idea as it hides the exception, OR
  • You can let the exception propagate.
  • I suppose a third option is to wrap the exception in an unchecked exception, but that just makes your interface murkier.

If you really want to defer error handling to the caller and not throw, the ideal solution is to implement a composite object to return, containing both the error status and the return value if there is one.

Best Practice: Using Java 8 Optional or throwing Exception

This basically boils down to: Does it make sense for this use-case for item to be missing?

Lets say say an app has users. User can add a phone number to his account info. As his prone number does not have to be there, you can use optional. Phone number might be there but might be missing. Client code has to handle Optional/nullable value.

On the other hand if I want to look at his email, which is a mandatory during registration. Then the exception is the way to go. Email must be there, but is not. Here client code faces invalid application state/corrupted user.

When to use exceptions and optionals in Swift error handling?

You should throw errors whenever details of the error are available, and they could be used in some way to recover the error.

For example, opening a file on the filesystem might fail because of an incorrect path, a permission error, or the file being the wrong type (e.g. a folder). A thrown error might include this information, but it won't really help, because there wouldn't be much your application could do with that information to recover from the error.

In your case, I think optionals are a good choice. However, you shouldn't repeat yourself:

guard let gameFromApi = GameFromApi(
id: gameApiResponse.id,
contestantsNames: gameApiResponse.contestants,
winnerName: gameApiResponse.winner,
confidence: 50,
conferencesNames: conferenceNamesInGame,
week: gameApiResponse.week
) else {
os_log("Could not unwrap new game object in loadGames(gameApiResponses:) in DataModelManager", type: .debug)
return GameFromApi()
}
return gameFromApi

How to do Java Optional if present do something or else throw?

As Guillaume F. already said in the comments, you could just use orElseThrow here:

Customer customer = customerRepository.findById(customer.getId())
.orElseThrow(() -> new Exception("customer not found"));
return customerRepository.save(customer);

By the way, avoid throwing Exception, as that exception is too broad. Use a more specific type, like NotFoundException.

Function throws AND returns optional.. possible to conditionally unwrap in one line?

Update: As of Swift 5, try? applied to an optional expression does not add another level of optionality, so that a “simple” optional binding is sufficient. It succeeds if the function did not throw an error and did not return nil. val is then bound to the unwrapped result:

if let val = try? getSomething() {
// ...
}

(Previous answer for Swift ≤ 4:) If a function throws and returns an optional

func getSomething() throws -> Value? { ... }

then try? getSomething() returns a "double optional" of the
type Value?? and you have to unwrap twice:

if let optval = try? getSomething(), let val = optval {

}

Here the first binding let optval = ... succeeds if the function did
not throw, and the second binding let val = optval succeeds
if the return value is not nil.

This can be shortened with case let pattern matching to

if case let val?? = try? getSomething() {

}

where val?? is a shortcut for .some(.some(val)).

Throw exception in optional in Java8

Optional is not intended for the purpose of dealing with exceptions, it was intended to deal with potential nulls without breaking the flow of your program. For example:

 myOptional.map(Integer::parseInt).orElseThrow(() -> new RuntimeException("No data!");

This will automatically skip the map step if the optional was empty and go right to the throw step -- a nice unbroken program flow.

When you write:

 myOptionalValue.orElseThrow(() -> new RuntimeException("Unavailable"));

... what you are really saying is: Return my optional value, but throw an exception if it is not available.

What you seem to want is a way to create an optional (that instantly catches the exception) and will rethrow that exception when you try using the optional.

How to avoid returning an optional after throwing an exception?

You can use Swift assert(_:_file:line:) function as follows

assert(some condition, "Message to display if condition is false (optional)" )

If the condition is verified the app will continue running, otherwise it will terminate



Related Topics



Leave a reply



Submit