Overcoming Type alias '…' references itself

Viewed 253

Background

I have an enum which, simplified, goes like this:

enum Container<T> {
  case a(T)
  case b(T)
  case c
}

I want to be able to instantiate this with a few different types for the generic and use typealias for that:

typealias IntContainer = Container<Int>
typealias FloatContainer = Container<Float>

Problem

So far, this is all fine. However, I also want to create a recursive instance of this:

typealias CyclicContainer = Container<CyclicContainer>

Swift reports this with a compile error:

Type alias 'CyclicContainer' references itself

… This error is still reported when I change the Container declaration to:

indirect enum Container<T>

This is a bit annoying, because this would be wholesome and compiling Swift:

indirect enum CyclicContainer {
  case a(CyclicContainer)
  case b(CyclicContainer)
  case c
}

Workaround 1

There is a work around for this. I can declare, for example:

indirect enum CyclicContainer {
   case container(Container<CyclicContainer>)
}

… However, this becomes awkward for concise descriptions of a CyclicContainer instance:

let cyclicContainer: CyclicContainer = .container(.a(.container(.b(.container(.c)))))

Instead of just:

let cyclicContainer: CyclicContainer = .a(.b(.c))

Workaround 2

I could also simply create a separate enum for the recursive case, as shown earlier:

indirect enum CyclicContainer {
    case a(CyclicContainer)
    case b(CyclicContainer)
    case c
}

However, I'll need to: create functions to convert between CyclicContainer and Container; re-implement various member functions that exist on Container<T>; and keep the two types in sync in future if I add a new case or change a case name.

This isn't terribly arduous and it's the approach I'm leaning towards. But it seems a shame to have to do this when Swift can handle an indirect enum completely happily, but not when its induced by instantiation of a generic argument on the enum.

Question

Is there a better way?

0 Answers
Related