Why does switch require a full declaration?

Hi


In this code

    func swipeGesture(sender: UISwipeGestureRecognizer)
    {
        let _: UISwipeGestureRecognizerDirection = .up
        let text: String
        switch sender.direction {
        case UISwipeGestureRecognizerDirection.right: text = "Right"
        case UISwipeGestureRecognizerDirection.left: text = "Left"
        case UISwipeGestureRecognizerDirection.up: text = "Up"
        case UISwipeGestureRecognizerDirection.down: text = "Down"
        default: text = "Unknown"
        }
        label.text = text
   


the compiler is happy to have the .up. but in the swtich it needs the whole huge name, thus defeating the aim of keeping swift code short. The compiler message if I take out UISwipeGestureRecognizerDirection and just leave .right is:

"Enum case 'right' not found in type 'UISwipeGestureRecognizerDirection'


Is this a bug in the compiler, or is there some reason for this that I am missing?

Accepted Reply

UISwipeGestureRecognizerDirection is not an enum, it’s an option set. Consider this:

let _: UISwipeGestureRecognizerDirection = [.up, .down]
let _: UISwipeGestureRecognizerDirection = [.up]
let _: UISwipeGestureRecognizerDirection = .up

The first line demonstrates that the option set can contain many values. The second line shows the ‘standard’ way of writing a single value option. The last line, the one you had, is a convenient way to write the second line.

All of the above work because the type declaration establishes a scope in which the compiler can look for values. This doesn’t work in a

switch
statement because a
switch
statement only creates that scope when you give it an enum (in the Swift grammar this is the difference between the expression-pattern and the enum-case-pattern).

The above just covers why UISwipeGestureRecognizerDirection behaves differently than a standard enum; it doesn’t really address the issue of whether this is just a current limitation or something more fundamental. I don’t know enough about the internals to comment on that. I recommend you file an enhancement for this to be improved and we’ll see where that gets you.

Please post your bug number, just for the record.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Replies

why do you deéclaire:

let _ : UISwipeGestureRecognizerDirection = .up


It seems it is nowhere used.


for the switch, you should try :


let dir : UISwipeGestureRecognizerDirection = sender.direction

switch dir {
case .up: 

}


PRobably the compiler has has problem with type inference.

That declation was just to demonstrate that I had the right types. I could copy and paste since it is a long type name, and the effect would persist.

UISwipeGestureRecognizerDirection is not an enum, it’s an option set. Consider this:

let _: UISwipeGestureRecognizerDirection = [.up, .down]
let _: UISwipeGestureRecognizerDirection = [.up]
let _: UISwipeGestureRecognizerDirection = .up

The first line demonstrates that the option set can contain many values. The second line shows the ‘standard’ way of writing a single value option. The last line, the one you had, is a convenient way to write the second line.

All of the above work because the type declaration establishes a scope in which the compiler can look for values. This doesn’t work in a

switch
statement because a
switch
statement only creates that scope when you give it an enum (in the Swift grammar this is the difference between the expression-pattern and the enum-case-pattern).

The above just covers why UISwipeGestureRecognizerDirection behaves differently than a standard enum; it doesn’t really address the issue of whether this is just a current limitation or something more fundamental. I don’t know enough about the internals to comment on that. I recommend you file an enhancement for this to be improved and we’ll see where that gets you.

Please post your bug number, just for the record.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

I did something like that, and that didn't work.

Thanks, that makes sense. I haven't fully come to grips with OptionSets yet. I had had the impression that a type didn't have to be an enum for that sort of shorter syntax to work, but I had to write it out in full even when I put this code into an extension of UISwipeGestureRecognizerDirection

I had had the impression that a type didn't have to be an enum for that sort of shorter syntax to work …

That’s actually correct in some cases. For example, this works:

if sender.direction == .up {
    …
}

because the compiler can infer the context in which to evaluate

.up
from the knowledge that both sides of the
==
operator must be the same type. Hence my “I don’t know enough about the internals” statement above; it’s possible that the compiler could be enhanced to do this in the expression-pattern variant of the
switch
statement, but I don’t know enough about how the compiler works to offer an opinion on that. OTOH, if you file an enhancement request it’ll make it’s way to someone who will know (-:

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

So, would


switch sender.direction { 
        case [.right] : text = "Right"


work ?

And indeed it does.

*Argh!* I could’ve sworn I tested this approach before writing my original response but I must have messed up the test somehow. I just re-tested it and it compiles just fine. I then changed my standard

Stream
event handling code from this:
func stream(_ thisStream: Stream, handle eventCode: Stream.Event) {
    …
    switch eventCode {
        case Stream.Event.openCompleted:
            …
        case Stream.Event.hasBytesAvailable:
            …
        case Stream.Event.hasSpaceAvailable:
            …
        case Stream.Event.endEncountered:
            …
        case Stream.Event.errorOccurred:
            …
        default:
            fatalError()
    }
}

to this:

func stream(_ thisStream: Stream, handle eventCode: Stream.Event) {
    …
    switch eventCode {
        case [.openCompleted]:
            …
        case [.hasBytesAvailable]:
            …
        case [.hasSpaceAvailable]:
            …
        case [.endEncountered]:
            …
        case [.errorOccurred]:
            …
        default:
            fatalError()
    }
}

and a) it still works, and b) it’s much nicer looking.

Thanks for setting us straight!

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Yes, thanks. I have adopted that style as well. I think we have been victims of the compiler being a bit too tricky. I don't see the need for the sytax without [ and ] to be made available.

Agree with this: this "flexible" syntax which seems a good idea to begin with just make things less clear at the end.