
Extending optionals in Swift - zacwood
https://www.swiftbysundell.com/posts/extending-optionals-in-swift
======
saagarjha
I’m not particularly impressed by of any of these extensions, because they
don’t seem to actually fix the underlying problems. I used to write code that
was overly defensive around Optionals, and I’d carefully do things like
wrapping in flatMap or throw guards in, but I’ve come to realize that this
just ends up hiding errors in the cases where you know something is supposed
to have a value. For this article in particular, I think there are better ways
to do what he’s trying to do:

For the converting an Optional to an error example, he could just put both
statements in one guard. Sure, being able to show that you’re passing a
function into another is pretty, but it really is overkill for something that
doesn’t even need an extension to Optional.

I think isNilOrEmpty, personally, just encourages papering over bad APIs: it
is never correct to represent an empty Collection with nil. UITextField.text
should never be nil (to the point where I think that this method is improperly
annotated; I can go check though); if it is your view hierarchy is in a state
where asking it for its text returns nil this should be a hard error because
you must have messed up somewhere. Just force unwrap in this case, and if
you’re designing an API, think twice about returning Collection?.

Lastly, get(orSet:) is just a skirting around the issue. Forget to set the
value of this view? Just set it again! Just ignore the fact that a clear logic
error that must have occurred if I ended up at a point where I’m trying to
access a view that doesn’t exist.

~~~
aaaaaaaaaab
These are my rules of thumb in priority order:

1\. Don’t use optionals.

2\. If you must use optionals due to technicalities (e.g. IBOutlet, weak
reference, etc.), make it implicitly-unwrapped.

3\. If you can’t make it implicitly unwrapped due to ‘nil’ being a legitimate
value, then use regular optionals, but force-unwrap it everywhere _except
where `nil` is expected to occur_.

There’s nothing worse than a codebase unnecessarily littered with

    
    
        guard let x = x else { return }
    

If my assumptions about some value were wrong, I want it to break as loud as
possible. Silently returning (or making up some silly default value like an
empty string or zero) is the worst thing you can do for yourself and your
colleagues. (Except if you’re a manager whose bonus is tied to your app’s
crash stats)

~~~
dkarbayev
Your approach seems to be a completely wrong use of optionals (have you been
writing in Java or any other language with implicit nullability?) since you’re
giving up type-safety of Swift. Do you use implicitly unwrapped optionals for
delegates too?

~~~
aaaaaaaaaab
>since you’re giving up type-safety of Swift

Giving up _type-safety_? Sorry, but I don't understand this in the current
context.

As for delegates: if the delegate can be 'nil' during normal operations, then
it should be a regular optional as per rule #3.

------
timjver
I'm not a huge fan of Optional.matching (also commonly called Optional.filter)
because you may want to "filter" non-optionals as well, i.e. T -> Optional<T>
given a predicate. Unfortunately Swift doesn't (yet?) allow writing extensions
on any generic T and the alternatives are a free function and an Optional
initialiser, neither of which allows you to easily chain them. (Another
alternative is a custom operator, but let's not.)

So perhaps the best we can do is Optional.matching as defined in the post,
combined with turning a non-optional into an optional using Optional(...) in
case we want to "filter" non-optional values using a predicate.

~~~
aplummer
> Unfortunately Swift doesn't (yet?) allow writing extensions on any generic T

I'm keen to understand the use case for this kind of code, where T literally
conforms to zero protocols. Would you not create a protocol with a default
implementation and then conform to that in this case? An example would help me
a lot!

------
Sharlin
I'm somewhat surprised that the Swift Optional doesn't come with `orElseThrow`
or `filter`. I mean, even the Java Optional has those combinators.

~~~
dep_b
filter -> flatMap / compactMap without arguments

orElseThrow is something you might need more often in Java, Swift handles
optionals with if let / else checks or Result enums instead of functions that
either result an object or throw an Exception. Throwing errors / exceptions is
pretty rare in the language compared to the Java / C# world.

Only when doing stuff like mapping JSON I set up try / throw trees because in
the end I might not care about the Error at all and just discard it.

~~~
stiGGG
And with Codable times of manually mapping JSON to objects are over, at least
you have to deal with something sane.

~~~
dep_b
I really needed stuff like snake_case support

~~~
bunnycorn
[https://developer.apple.com/documentation/foundation/jsonenc...](https://developer.apple.com/documentation/foundation/jsonencoder/keyencodingstrategy/converttosnakecase)

Also, as already said, CodingKeys.

~~~
dep_b
Right, I said _needed_ , not need ;)

