How do you switch on a noncopyable type?

my perception of the proposed @noncopyable goes through cycles of hype and despair.

@_moveOnly
enum Enum
{
    case a(Int)
    case b(Int)
    case c(Int)
}
extension Enum
{
    var name:Character
    {
        switch self
        {
        case .a: return "a"
        case .b: return "b"
        case .c: return "c"
        }
    }
}
error: 'self' has guaranteed ownership but was consumed
    {
    ^
note: consuming use
        switch self
        ^

okay. i get that switch makes a new binding, which probably we care about if the associated values are themselves noncopyable. so maybe… this?

extension Enum
{
    var name:Character
    {
        switch self
        {
        case .a(let value): self = .a(value) ; return "a"
        case .b(let value): self = .b(value) ; return "b"
        case .c(let value): self = .c(value) ; return "c"
        }
    }
}

nope, the compiler doesn’t like that either:

error: cannot assign to value: 'self' is immutable
        case .a(let value): self = .a(value) ; return "a"
                            ^~~~
error: cannot assign to value: 'self' is immutable
        case .b(let value): self = .b(value) ; return "b"
                            ^~~~
error: cannot assign to value: 'self' is immutable
        case .c(let value): self = .c(value) ; return "c"
                            ^~~~

it must become:

extension Enum
{
    var name:Character
    {
        mutating get
        {
            switch self
            {
            case .a(let value): self = .a(value) ; return "a"
            case .b(let value): self = .b(value) ; return "b"
            case .c(let value): self = .c(value) ; return "c"
            }
        }
    }
}

surely there there must be an easier way?

1 Like

Currently, switch is always consuming; for clarity, and because this state of affairs is certainly not the desired default for switching over a noncopyable value, the language steering group has decided that switch consume foo will be the required spelling for a consuming switch over a noncopyable foo.

There are open design questions about if and how a non-consuming switch can be made the default in the language. It has not escaped our attention, though, that this is a missing feature.

6 Likes