Interesting, but I’m unsure if all of it is significantly better than just using the guard that is effectively inside of the operator/func that is being proposed:
guard let value = Int("NotANumber") else { throw InitializerError.invalidString } It is only a couple of characters longer and already works (it’s what I use currently). If guard allowed for a special single-expression variation so that you didn’t need to specify the ugly braces or something, it’d look prettier and be nice for a lot of other situations, too: guard let value = Int("NotANumber") else: throw InitializerError.invalidString guard someVal < 10 else: return false guard mustBeTrue() else: return // etc Not to derail this, but I sort of want this ability anywhere as a shorthand for a single-expression block. if something < 42: doThing() for a in list: print(a) But I imagine that’ll never fly. :P l8r Sean > On Apr 6, 2016, at 9:46 AM, Erica Sadun via swift-evolution > <swift-evolution@swift.org> wrote: > > Pyry Jahkola and I have been plugging away on the following which is > preliminary enough not to qualify as an actual draft. He prefers the Mike Ash > approach. I prefer the operator approach. So we have not actually settled on > which one we would actually propose despite how I've written this up. > > I'm putting this out there to try to gain a consensus on: > > * Would this be a viable proposal? > * If so, which of the options would work best within Swift's design and > philosophy > > Thanks for your feedback. > > -- Erica > Introduction > > Swift's try? keyword transforms error-throwing operations into optional > values. We propose adding an error-throwing nil-coalescing operator to the > Swift standard library. This operator will coerce optional results into > Swift's error-handling system. > > This proposal was discussed on the Swift Evolution list in the name thread. > > Motivation > > Any decision to expand Swift's set of standard operators should be taken > thoughtfully and judiciously. Moving unaudited or deliberately > non-error-handling nil-returning methods and failable initializers into > Swift's error system should be a common enough use case to justify > introducing a new operator. > > Detail Design > > We propose adding a new operator that works along the following lines: > > infix operator ??? {} > > func ???<T>(lhs: T?, @autoclosure error: () -> ErrorType) throws -> T { > guard case let value? = lhs else { throw error() } > return value > } > > The use-case would look like this: > > do { > let error = Error(reason: "Invalid string passed to Integer initializer") > let value = try Int("NotANumber") ??? InitializerError.invalidString > print("Value", value) > } catch { print(error) } > > Note > > SE-0047 (warn unused result by default) and SE-0049 (move autoclosure) both > affect many of the snippets in this proposal > > Disadvantages to this approach: > > • It consumes a new operator, which developers must be trained to use > • Unlike many other operators and specifically ??, this cannot be > chained. There's no equivalent to a ?? b ?? c ?? dor a ?? (b ?? (c ?? d)). > Alternatives Considered > > Extending Optional > > The MikeAsh approach extends Optional to add an orThrow(ErrorType) method > > extension Optional { > func orThrow(@autoclosure error: () -> ErrorType) throws -> Wrapped { > guard case let value? = self else { throw error() } > return value > } > } > > Usage looks like this: > > do { > let value = try Int("NotANumber") > .orThrow(InitializerError.invalidString) > print("Value", value) > } catch { print(error) } > > An alternative version of this call looks like this: optionalValue.or(throw: > error). I am not a fan of using a verb as a first statement label. > > Disadvantages: > > • Wordier than the operator, verging on claustrophobic, even using > Swift's newline dot continuation. > • Reading the code can be confusing. This requires chaining rather than > separating error throwing into a clear separate component. > Advantages: > > • No new operator, which maintains Swift operator parsimony and avoids > the introduction and training issues associated with new operators. > • Implicit Optional promotion cannot take place. You avoid mistaken > usage like nonOptional ??? error and nonOptional ?? raise(error). > • As a StdLib method, autocompletion support is baked in. > Introducing a StdLib implementation of raise(ErrorType) > > Swift could introduce a raise(ErrorType) -> T global function: > > func raise<T>(error: ErrorType) throws -> T { throw error } > > do { > let value = try Int("NotANumber") ?? raise(InitializerError.invalidString) > print("Value", value) > } catch { print(error) } > > This is less than ideal: > > • This approach is similar to using && as an if-true condition where an > operator is abused for its side-effects. > • It is wordier than the operator approach. > • The error raising function promises to return a type but never will, > which seems hackish. > Overriding ?? > > We also considered overriding ?? to accept an error as a RHS argument. This > introduces a new way to interpret ?? as meaning, "throw this error instead of > substituting this value". > > func ??<T>(lhs: T?, @autoclosure error: () -> ErrorType) throws -> T { > guard case let value? = lhs else { throw error() } > return value > } > > Usage: > > let value = try Int("NotANumber") ?? Error(reason: "Invalid string passed to > Integer initializer") > > This approach overloads the semantics as well as the syntax of the coalescing > operator. Instead of falling back to a RHS value, it raises the RHS error. > The code remains simple and readable although the developer must take care to > clarify through comments and naming which version of the operator is being > used. > > • While using try in the ?? statement signals that a throwing call is > in use, it is insufficient (especially when used in a throwing scope) to > distinguish between the normal coalescing and new error-throwing behaviors. > • Error types need not use the word "Error" in their construction or > use. For example try value ?? e may not be immediately clear as an > error-throwing intent. > • Overloading ?? dilutes the impact and meaning of the original > operator intent. > Future Directions > > We briefly considered something along the lines of perl's die as an > alternative to raise using fatalError. > > Acknowledgements > > Thanks Mike Ash, Jido, Dave Delong > _______________________________________________ > swift-evolution mailing list > swift-evolution@swift.org > https://lists.swift.org/mailman/listinfo/swift-evolution _______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution