Pitch: disallow `()` from Switch statement case satisfaction


(Erica Sadun) #1

I thought this was long gone but today I found out it is still legal:

switch i {
case 4 ... 6: ()
case 3: print("Here")
default: break
}

Is there a motivating factor for keeping this in the language? The compiler picks up on Void and emits an error. You'd think () would produce the same results but it doesn't.

-- Erica


(Xiaodi Wu) #2

Well, unless I'm mistaken, `()` here is a value. I can replace it with `3`
and the compiler emits a warning about unused results. I'm guessing that
since () is a value of type Void, the warning about unused results isn't
triggered.
While it's true that `Void` causes an error, I can write `Void()` instead
and everything compiles just fine, which is what the `()` is doing too.
Seems fine to me?

···

On Tue, Oct 11, 2016 at 1:43 PM, Erica Sadun via swift-evolution < swift-evolution@swift.org> wrote:

I thought this was long gone but today I found out it is still legal:

switch i {
case 4 ... 6: ()
case 3: print("Here")
default: break
}

Is there a motivating factor for keeping this in the language? The
compiler picks up on Void and emits an error. You'd think () would produce
the same results but it doesn't.

-- Erica

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Haravikk) #3

Hopefully I'm not the only one but… how are we supposed to be doing this? Because () is exactly what I've been using the entire time for cases that I want to ignore (or are handled in code outside the switch). I'm going to have a few dozen files to edit if there's something else I'm supposed to be using…

···

On 11 Oct 2016, at 19:43, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

I thought this was long gone but today I found out it is still legal:

switch i {
case 4 ... 6: ()
case 3: print("Here")
default: break
}

Is there a motivating factor for keeping this in the language? The compiler picks up on Void and emits an error. You'd think () would produce the same results but it doesn't.

— Erica


(Robert Widmann) #4

I agree, though it may seem counterintuitive at first. () is a value of unit type that exists here to satisfy the sema’s requirements that all branches are destructive, productive or defer to another productive branch.

~Robert Widmann

···

On Oct 11, 2016, at 2:54 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

Well, unless I'm mistaken, `()` here is a value. I can replace it with `3` and the compiler emits a warning about unused results. I'm guessing that since () is a value of type Void, the warning about unused results isn't triggered.
While it's true that `Void` causes an error, I can write `Void()` instead and everything compiles just fine, which is what the `()` is doing too. Seems fine to me?

On Tue, Oct 11, 2016 at 1:43 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
I thought this was long gone but today I found out it is still legal:

switch i {
case 4 ... 6: ()
case 3: print("Here")
default: break
}

Is there a motivating factor for keeping this in the language? The compiler picks up on Void and emits an error. You'd think () would produce the same results but it doesn't.

-- Erica

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Alex Blewitt) #5

You can have a 'break' there, which is equivalent to a nop but without a return value. Whether that's what you're supposed to do or not is a different issue :slight_smile:

Alex

···

On 13 Oct 2016, at 11:06, Haravikk via swift-evolution <swift-evolution@swift.org> wrote:

On 11 Oct 2016, at 19:43, Erica Sadun via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I thought this was long gone but today I found out it is still legal:

switch i {
case 4 ... 6: ()
case 3: print("Here")
default: break
}

Is there a motivating factor for keeping this in the language? The compiler picks up on Void and emits an error. You'd think () would produce the same results but it doesn't.

— Erica

Hopefully I'm not the only one but… how are we supposed to be doing this? Because () is exactly what I've been using the entire time for cases that I want to ignore (or are handled in code outside the switch). I'm going to have a few dozen files to edit if there's something else I'm supposed to be using…


(Erica Sadun) #6

Fair enough. I defer to both of you.

Thanks, -- E

···

On Oct 11, 2016, at 1:41 PM, Robert Widmann <devteam.codafi@gmail.com> wrote:

I agree, though it may seem counterintuitive at first. () is a value of unit type that exists here to satisfy the sema’s requirements that all branches are destructive, productive or defer to another productive branch.

~Robert Widmann

On Oct 11, 2016, at 2:54 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Well, unless I'm mistaken, `()` here is a value. I can replace it with `3` and the compiler emits a warning about unused results. I'm guessing that since () is a value of type Void, the warning about unused results isn't triggered.
While it's true that `Void` causes an error, I can write `Void()` instead and everything compiles just fine, which is what the `()` is doing too. Seems fine to me?

On Tue, Oct 11, 2016 at 1:43 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
I thought this was long gone but today I found out it is still legal:

switch i {
case 4 ... 6: ()
case 3: print("Here")
default: break
}

Is there a motivating factor for keeping this in the language? The compiler picks up on Void and emits an error. You'd think () would produce the same results but it doesn't.

-- Erica

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Chris Lattner) #7

Right, I’d recommend using “break” for a case that you’re intentionally ignoring. That communicates clearly to someone maintaining the code that you thought about it and are intentionally ignoring it (or bailing out before other cases could match it).

-Chris

···

On Oct 13, 2016, at 4:26 AM, Alex Blewitt via swift-evolution <swift-evolution@swift.org> wrote:

On 13 Oct 2016, at 11:06, Haravikk via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On 11 Oct 2016, at 19:43, Erica Sadun via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I thought this was long gone but today I found out it is still legal:

switch i {
case 4 ... 6: ()
case 3: print("Here")
default: break
}

Is there a motivating factor for keeping this in the language? The compiler picks up on Void and emits an error. You'd think () would produce the same results but it doesn't.

— Erica

Hopefully I'm not the only one but… how are we supposed to be doing this? Because () is exactly what I've been using the entire time for cases that I want to ignore (or are handled in code outside the switch). I'm going to have a few dozen files to edit if there's something else I'm supposed to be using…

You can have a 'break' there, which is equivalent to a nop but without a return value. Whether that's what you're supposed to do or not is a different issue :)


(Haravikk) #8

Perhaps too philosophical a question? ^^

You're right though, I probably should be using breaks as they're more explicit, and I suppose fallthrough should work too so all cases should be covered without having to use (), in that case it maybe is something worth getting rid of?

···

On 13 Oct 2016, at 12:26, Alex Blewitt <alblue@apple.com> wrote:

On 13 Oct 2016, at 11:06, Haravikk via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On 11 Oct 2016, at 19:43, Erica Sadun via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I thought this was long gone but today I found out it is still legal:

switch i {
case 4 ... 6: ()
case 3: print("Here")
default: break
}

Is there a motivating factor for keeping this in the language? The compiler picks up on Void and emits an error. You'd think () would produce the same results but it doesn't.

— Erica

Hopefully I'm not the only one but… how are we supposed to be doing this? Because () is exactly what I've been using the entire time for cases that I want to ignore (or are handled in code outside the switch). I'm going to have a few dozen files to edit if there's something else I'm supposed to be using…

You can have a 'break' there, which is equivalent to a nop but without a return value. Whether that's what you're supposed to do or not is a different issue :slight_smile:


(Erica Sadun) #9

This brings up a particular pet peeve of mine in terms of ability (or lack thereof) to communicate about returns from closures.

func forInExample() -> String {
    for _ in [1, 2, 3] {
        return "Inner"
    }
    return "Outer"
}

let y = forInExample() // Inner

func forEachExample() -> String {
    [1, 2, 3].forEach { _ in
        return "Inner"
    }
    return "Outer"
}

let x = forEachExample() // "Outer"

In Objective-C, it was possible to create a `blockReturn` macro and substitute it for block `return` statements. This customization cannot be duplicated in Swift without a change to the language. In regard to clear communication to code maintainers, this issue is problematic, although it's mitigated by strict adherence to the "Rule of Kevin" (parens around functional closures, none around procedural ones)

-- E

···

On Oct 13, 2016, at 9:31 AM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Oct 13, 2016, at 4:26 AM, Alex Blewitt via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On 13 Oct 2016, at 11:06, Haravikk via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On 11 Oct 2016, at 19:43, Erica Sadun via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I thought this was long gone but today I found out it is still legal:

switch i {
case 4 ... 6: ()
case 3: print("Here")
default: break
}

Is there a motivating factor for keeping this in the language? The compiler picks up on Void and emits an error. You'd think () would produce the same results but it doesn't.

— Erica

Hopefully I'm not the only one but… how are we supposed to be doing this? Because () is exactly what I've been using the entire time for cases that I want to ignore (or are handled in code outside the switch). I'm going to have a few dozen files to edit if there's something else I'm supposed to be using…

You can have a 'break' there, which is equivalent to a nop but without a return value. Whether that's what you're supposed to do or not is a different issue :slight_smile:

Right, I’d recommend using “break” for a case that you’re intentionally ignoring. That communicates clearly to someone maintaining the code that you thought about it and are intentionally ignoring it (or bailing out before other cases could match it).

-Chris


#10

If I might be so bold, perhaps we should consider the opposite. Suppose you
have a conditional statement inside a loop. It would be easier for the
reader to understand what it does if “break” meant the same thing
regardless of whether you used “if” or “switch” for the condition.

Right now, these two loops behave differently:

let seq = [1, 2, 3]

for x in seq { // prints ! 2 ! 3 !
    switch x {
    case 1: break
    case _: print(x)
    }
    print("!")
}

for x in seq { // prints nothing
    if x == 1 {
        break
    } else {
        print(x)
    }
    print("!")
}

In particular, the current behavior of “break” means you need to label the
loop if you want to break out of it from a “switch”, but not from an “if”.
This is at least inconsistent.

Nevin

···

On Thu, Oct 13, 2016 at 7:59 AM, Haravikk via swift-evolution < swift-evolution@swift.org> wrote:

On 13 Oct 2016, at 12:26, Alex Blewitt <alblue@apple.com> wrote:

On 13 Oct 2016, at 11:06, Haravikk via swift-evolution < > swift-evolution@swift.org> wrote:

On 11 Oct 2016, at 19:43, Erica Sadun via swift-evolution < > swift-evolution@swift.org> wrote:

I thought this was long gone but today I found out it is still legal:

switch i {
case 4 ... 6: ()
case 3: print("Here")
default: break
}

Is there a motivating factor for keeping this in the language? The
compiler picks up on Void and emits an error. You'd think () would produce
the same results but it doesn't.

— Erica

Hopefully I'm not the only one but… how are we *supposed* to be doing
this? Because () is exactly what I've been using the entire time for cases
that I want to ignore (or are handled in code outside the switch). I'm
going to have a few dozen files to edit if there's something else I'm
supposed to be using…

You can have a 'break' there, which is equivalent to a nop but without a
return value. Whether that's what you're supposed to do or not is a
different issue :slight_smile:

Perhaps too philosophical a question? ^^

You're right though, I probably should be using breaks as they're more
explicit, and I suppose fallthrough should work too so all cases should be
covered without having to use (), in that case it maybe is something worth
getting rid of?

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Haravikk) #11

That's an interesting point, but seems like it might be better covered by using a different keyword; e.g- we could use "end" for a loop and "break" for a switch? "End" feels more consistent with "continue", but we get into the pesky "terms of art" territory =)

I don't think that requiring use of () is the right solution though, as it is admittedly kind of strange, I just seem to have picked up it in one tutorial and then never stopped using it =D

···

On 13 Oct 2016, at 16:19, Nevin Brackett-Rozinsky via swift-evolution <swift-evolution@swift.org> wrote:

If I might be so bold, perhaps we should consider the opposite. Suppose you have a conditional statement inside a loop. It would be easier for the reader to understand what it does if “break” meant the same thing regardless of whether you used “if” or “switch” for the condition.

Right now, these two loops behave differently:

let seq = [1, 2, 3]

for x in seq { // prints ! 2 ! 3 !
    switch x {
    case 1: break
    case _: print(x)
    }
    print("!")
}

for x in seq { // prints nothing
    if x == 1 {
        break
    } else {
        print(x)
    }
    print("!")
}

In particular, the current behavior of “break” means you need to label the loop if you want to break out of it from a “switch”, but not from an “if”. This is at least inconsistent.

Nevin