[swift-evolution] [Pitch] Throwing unwrap operators

Gor Gyolchanyan gor.f.gyolchanyan at icloud.com
Sun Jul 30 14:09:29 CDT 2017


That seems like a straight-forward way of plugging that particular hole in the ”less-than-normal” feature set of Swift.
I do, however, think that ??? Is not a great choice, because it doesn’t indicate the error handling at all.
Considering that the traditional ?? means “unwrap optional or use the other value’,  I’d go for something along the lines of ?throw that means “unwrap optional or throw error”.

func foo() throws -> String {
	return bar ?throw EmbarrassingError.oops
}

But there are other holes in completeness of Swift’s features that are closely related to this.

I opened a discussion a while back regarding something similar, but that discussion got abandoned without a conclusion.
In a nutshell, I proposed making `throws` and `inout` less magical by promoting them to proper declaration specifiers.
Currently, something like 

var foo: inout String = &bar

can be exactly replicated in the following way:

var foo: String {
	get {
		return bar
	}
	
	set {
		bar = newValue
	}
}

So the would be just some minor syntax sugar for logical completeness and convenience.
Further helping the logical completeness of `inout` would be allowing functions to have a `get` and `set` accessors just like subscripts. This would allow implementing a `set` accessor of the function, essentially making it an `inout` function with all the usual perks like the prefix ampersand operator.

The `throws` could get the same treatment by first allowing property accessors to be marked as `throws`:

var foo: String throws {
	return try throwingFunction()
}

print(try foo)

Then getting a syntax sugar just like `inout`:

var foo: String throws = throwingFunction() // notice the lack of `try`, due to the fact that the error from `throwingFunction()` is not thrown into the current scope.

In cases where the getter and setter of the variable can have different thowing capabilities, the trick used by access level indicators could be used:

var foo: String throws(set)

or

var foo: String throws(get)

What do you think?

> On Jul 30, 2017, at 9:37 PM, Erica Sadun <erica at ericasadun.com> wrote:
> 
> From 2016:
> 
> See: https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160404/014272.html <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160404/014272.html>
> and https://gist.github.com/erica/5a26d523f3d6ffb74e34d179740596f7 <https://gist.github.com/erica/5a26d523f3d6ffb74e34d179740596f7>
> 
> -- E
> 
>> On Jul 30, 2017, at 12:30 PM, Gor Gyolchanyan via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>> 
>> I like the general direction where this is going, but I haven’t settled on an opinion regarding its appearance yet.
>> I’ve argued before that the gap between optionals and errors should be closed by making it easy to swift from optionals to non-optionals with throwing.
>> The “unwrap-or-die” idea discussed earlier is very similar to this.
>> 
>> In the end, I think all optional, throwing and fatalError-related proposals have to be united and carefully considered as an overarching proposal to extend and complete Swift’s representation of “less-than-normal” situations.
>> 
>>> On Jul 30, 2017, at 9:25 PM, Robert Bennett via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>> 
>>> This idea was sparked by conversation in another thread about a more concise way to write the following:
>>> 
>>> guard let x1 = f1(), let x2 = f2(), ... else { ... }
>>> doSomething(with: x1)
>>> doSomething(with: x2)
>>> ...
>>> 
>>> It was suggested to write a function that throws when an optional is nil, and then wrapping the calls to f1, f2, ... in that function, and then wrapping *those* in a do-catch block. This would both exit early in case one value was nil, and also use the values as soon as they’re available instead of needing to assign them to a temp variable first and using the temp variable.
>>> 
>>> Instead of a throwing unwrap function, I am proposing a throwing unwrap operator. This operator would work like !, but instead of a fatal error when the value is nil, it would throw.
>>> 
>>> struct UnwrapError: Error {}
>>> postfix operator ^?
>>> extension Optional {
>>>  static postfix func ^?(optional: Optional) throws -> Wrapped {
>>>      guard let wrapped = optional else {
>>>          throw UnwrapError()
>>>      }
>>>      return wrapped
>>>  }
>>> }
>>> 
>>> In addition, to round this out, I think it would be helpful to be able to throw arbitrary errors, as a nil value may carry meaning that should be propagated to the rest of the program. Thus there could be a throwing nil coalescing operator, which returns the unwrapped value if non-nil, or throws the specified error if nil.
>>> 
>>> infix operator ^??
>>> extension Optional {
>>>  static func ^??(lhs: Optional, rhs: Error) throws -> Wrapped {
>>>      guard let wrapped = lhs else {
>>>          throw rhs
>>>      }
>>>      return wrapped
>>>  }
>>> }
>>> 
>>> Thoughts? I think these would be helpful additions to allow doing something with Optionals while simultaneously exiting early in the case of a nil value — putting the unwrapping, the use, and the exiting early all on one line. 
>>> 
>>> Hopefully this doesn’t distract from the other important conversations happening on the mailing list!
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>> 
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170730/e838423e/attachment.html>


More information about the swift-evolution mailing list