You want something like Swift that it cannot do. In particular, as far as I know, Swift has no union types. If you want something like this, you can look at functional or functionally-inspired languages.
Interlude: if both types are structures or classes (i.e. not protocols), you can use this template:
protocol DataOrError {}
extension Data: DataOrError {}
extension ErrorClass: DataOrError {}
Assuming there are no other protocol developers, now you have something that fits the type of union. You can also switch between types:
switch doe {
case let e as Error: print("Error \(e)")
case let d as Data: print("Data \(d)")
default: assert(false, "thou shalt not implement my dummy!")
}
In any case, we can fake it using enumerations with related values, which can (with restrictions) be used as a type of association of the poor.
Define the enumeration as follows:
enum DataOrError {
case Data(Data)
case Error(Error)
}
DataOrError, , , () Data Error DataOrError? .
Caller-site, - :
extension String: Error {}
func myFunction(completion: (DataOrError) -> ()) {
completion(.Data(Data(bytes: [1,2,3,4,5])))
completion(.Error("this won't work!"))
}
-:
var myCompletion = { (doe: DataOrError) in
switch doe {
case .Data(let d): print("Data \(d)")
case .Error(let e): print("Error \(e)")
}
}
myFunction(completion: myCompletion)
. , , , OR Error. , .
struct TalkativeOptional<T> {
private(set) var rawValue: T?
private(set) var error: Error?
init(value: T) {
self.rawValue = value
}
init(error: Error) {
self.error = error
}
}
, nil. ; , , .
-:
func convert(_ number: String) -> TalkativeOptional<Int> {
if let int = Int(number) {
return TalkativeOptional(value: int)
} else {
return TalkativeOptional(error: "'\(number)' not a valid integer!")
}
}
:
var a = convert("dsa2e2")
if let val = a.rawValue {
print("a + 1 = \(val + 1)")
} else { // we know by design that error is set!
print("ERROR: \(a.error!)")
}