Without commenting on the larger proposal, I’ll note that while throw
is a statement today, there’s nothing that requires it to be one. Since you can already put try immediatelyThrow(error)
into expression position I don’t think there’s any ideological reason to keep throw error
from being a valid expression.
+1 for this, I'm using it for several years. Here is the sample:
extension Optional {
public func unwrapOrThrow(_ errorExpression: @autoclosure () -> Error) throws -> Wrapped {
guard let value = self else { throw errorExpression() }
return value
}
public func unwrapOrThrow(_ errorExpression: () -> Error) throws -> Wrapped {
guard let value = self else { throw errorExpression() }
return value
}
}
// Usage:
let url = try urlComponents.url.unwrapOrThrow(AppLinkError(code: .unexpectedNilURL))
let deepLinkString = try (deepLinkURLValue as? String).unwrapOrThrow(AppLinkError(code: .typeCastFailed))
Using #file and #line is not good default option, because it increases binary size. As a tradeoff optional values win nil default value can be used.
public func unwrapOrThrow(_ errorExpression: @autoclosure () -> Error, file: StaticString? = nil, line: UInt? = nil) throws -> Wrapped
let value = try optional.unwrapOrThrow(MyError())
let value = try optional.unwrapOrThrow(MyError(), file: #fileID, line: #line)
-1 here. I'm not seeing the need for a new operator. I'm doing this for years and it works/chains great:
try URL(string: "https://google.com").unwrap()
. You could overload .unwrap()
to satisfy all scenarios above, and in a clearer way (i.e. using named params).
Personally, I would be in favour of adding an .unwrap()
method (or similar) on Optional
, since this is something I use in almost all my projects. Not sure how it would fit others tho.
Same here. I don't like adding a new operator for this. Seems like most of us already use this "unwrap or throw" method on Optional
and are happy with it. And yes, I would like to have the standard library featuring this method.
An unwrapOrThrow
method certainly plays nicer with the pre-existing ability to put a Never
returning function on the left hand side of ??
. It's also slightly more explicit about the fact that the supplied error will be thrown.
Recently, someone pointed out to me that, if you squint a lot, Optional
is just Result
where Failure
is nil
kind of thing. Given this, the "correct" function to use would be try get()
.
Using the following generic conversion functions foo!
is equivalent to try! foo.get()
with try? foo.get()
being a full round trip.
public extension Optional {
enum UnwrappingError : Error {
case foundNilWhileUnwrappingAnOptionalValue
}
func get(orThrow error: @autoclosure () -> Error = UnwrappingError.foundNilWhileUnwrappingAnOptionalValue) throws -> Wrapped {
if let value = self {
return value
} else {
throw error()
}
}
}
public extension Result {
init(_ optional: Success?, failure: @autoclosure () -> Failure) {
if let success = optional {
self = .success(success)
} else {
self = .failure(failure())
}
}
}
public extension Result where Failure == Error {
init(_ optional: Success?) {
self = Result {
try optional.get()
}
}
}
It is indeed. If Result was there first we would probably not invent Optional.
Why would I want to use a longer try! foo.get()
than a shorter foo!
?
Very much agree, I was just pointing out that they are equivalent rather than suggesting one use the longer form.
Another example is if let foo = foo
being equivalent to if case let .some(foo) = foo
, although again that shows the similarity's between Optional
and Result
.
unwrap() is enough
extension Optional {
@discardableResult
@_transparent
public func unwrap(_ message: @autoclosure () -> String = String(),
fileID: StaticString = #fileID, line: UInt = #line, column: UInt = #column) throws -> Wrapped {
try unwrap(ErrorInCode(header: "Unwrap failed", message: message(), location: CodeLocation(fileID: fileID, line: line, column: column)))
}
@discardableResult
@_transparent
public func unwrap<E: Error>(_ error: @autoclosure () -> E) throws -> Wrapped {
guard let value = self else {
throw error()
}
return value
}
}