Can we have inheritable sum-types?

Hello, I wanted to implement some fine pattern of stateful types so the following code was written

protocol StatefulType {
    associatedtype State 
    var currentState: State { get } // lets pretend that it is always enum
}
class File: StatefulType {
    public class Opened {
        var fileHandle = "some"
    }
    public class Closed {}
    public enum State {
        case opened(Opened)
        case closed(Closed)
    }
    private(set) var currentState: State

    init() {currentState = .opened(.init())}
}
class SpecFile: File {
    enum SpecState {
        case opened(SpecOpened)
        case closed(SpecOpened)
        case somethingDifferent
    }
    class SpecOpened: Opened {}
    class SpecClosed: Closed {}
    override var currentState: SpecState
    override init() {
        currentState = .somethingDifferent
    }
}

The fun part is that it cant compile, because compiler complaints about incompatibility of SpecState and State. The most obvious solution would be to allow enum cases to be inherited, but I found out that it's not possible. A quick search on forums showed that I was not the only one who encountered the problem , so I want to know from folks around whether it is going anywhere. thank in advance.

What do you expect to happen if an instance of SpecFile whose currentState is .somethingDifferent, gets used as an instance of File, where its currentState is accessed as a State, not a SpecState?

That is to say, you have the inheritance of sum types entirely backwards. If it were possible for one enum to be a subtype of another, it could only mean that the subtype is a refinement, not an expansion. In other words, the supertype would have more cases, and the subtype would have fewer.

Adding cases as you have shown would violate the Liskov substitution principle.

4 Likes

Which, it's worth noting, has indeed been proposed/discussed in the past!

1 Like

well, then an explicit variance for call sites is the thing which would be appreciated as well.