5 ms·
Extending optionals in Swift
- timjver 8y agoI'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.
- aaaaaaaaaab 8y agoUniform Call Syntax would solve this elegantly: https://en.m.wikipedia.org/wiki/Uniform_Function_Call_Syntax https://en.m.wikipedia.org/wiki/Uniform_Function_Call_Syntax
- aplummer 8y ago> 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!
- iBelieve 8y agoThe way I do this in Rust is `Some(...).filter(...)`. I personally like this over having generic extensions, as it makes it very clear that its doing filtering that produces an optional, rather than filtering through a list or other iterable.
- Sharlin 8y agoI'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 8y agofilter -> 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 8y agoAnd with Codable times of manually mapping JSON to objects are over, at least you have to deal with something sane.
- dep_b 8y agoI really needed stuff like snake_case support
- saagarjha 8y agoCodableKeys should let you handle this.
- bunnycorn 8y agohttps://developer.apple.com/documentation/foundation/jsonencoder/keyencodingstrategy/converttosnakecase https://developer.apple.com/documentation/foundation/jsonenc... Also, as already said, CodingKeys.
- dep_b 8y agoRight, I said needed, not need ;)
- saagarjha 8y agoI’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.
- tabs_masterrace 8y agoAgree with most of it, having .(unwrap)orThrow() seems nice syntax sugar though.
- aaaaaaaaaab 8y agoThese 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)