Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the exact limitation on generic associated values in Swift enums?

I am trying to understand the exact limits on enums with generic associated values in Swift.

You might think that they are supported, since Optional is such a type. Here is the code defining Optional in the Swift standard library:

enum Optional<T> : Reflectable, NilLiteralConvertible {
    case None
    case Some(T)
// ...
}

It seems like the case member Some has an associated value of variable type T, right?

However, it is mentioned in the book Functional Programming in Swift (p 87), that such types are not supported:

We would like to define a new enumeration that is generic in the result associated with Success:

enum Result<T> {
    case Success(T)
    case Failure(NSError) 
} 

Unfortunately, generic associated values are not supported by the current Swift compiler.

And indeed, if you type that snippet into the compiler, you get an error (error: unimplemented IR generation feature non-fixed multi-payload enum layout).

So what is going on here? Is it just that it is not supported in general, but is supported for Optional as a special case? Is there any way to see how Optional receives this special support? Or if other standard library types also get special support?

like image 655
algal Avatar asked Dec 02 '14 19:12

algal


1 Answers

In Swift 2 (as part of Xcode 7), there is no limitation on associated values. So, feel free to dance to beats like this:

enum YouCanGoWith<T, U> {
    case This(T)
    case That(U)
    case Us
}

Now, if you're looking for a Success-or-Error kind of enum, you might want to stop and think about why... because Swift 2 also brings a new error handling model. So you don't need such a type as the return value of your functions — you can just declare it like so:

func walkWith(rhythm: Bool) throws -> Place { /* ... */ }

...and if your function succeeds, the caller always gets a (non-optional) Place for walken to. And — separately from using the result — the caller decides how to handle, swallow, or propagate the error.

For details on that, see Error Handling in The Swift Programming Language. Look closely — the syntax looks a bit like the exception model you see in some other languages, but Swift errors are an entirely different kind of animal.

(Of course, the throws model is specific to synchronous calls. If instead you're declaring callbacks for asynchronous processes, where the callback closure receives either the result of successful asynchronous work or an error — a Success-or-Error type is still entirely appropriate.)

like image 189
rickster Avatar answered Sep 21 '22 14:09

rickster