[swift-evolution] Proposal: Allow #if to guard switch case clauses

rintaro ishizaki fs.output at gmail.com
Wed May 10 03:32:03 CDT 2017


Hi evolution community,

This proposal allows you to enclose switch cases with #if directive.
Implementation: https://github.com/apple/swift/pull/9457
This is one of the oldest SR issue:
https://bugs.swift.org/browse/SR-2
https://bugs.swift.org/browse/SR-4196

Thanks!
Rintaro


Allow #if to guard switch case clauses

   - Proposal: SE-NNNN <https://gist.github.com/rintaro/NNNN-filename.md>
   - Authors: Rintaro Ishziaki <https://github.com/rintaro>
   - Review Manager: TBD
   - Status: Awaiting review

<https://gist.github.com/rintaro/a5a9d9836027d7df7a5326a3a8cf9d89#introduction>
Introduction

This proposal adds ability to guard switch case clauses with #if directives.

Swift-evolution thread: Not yet
<https://lists.swift.org/pipermail/swift-evolution/>
<https://gist.github.com/rintaro/a5a9d9836027d7df7a5326a3a8cf9d89#motivation>
Motivation

When you want to switch cases only for certain compilation condition, say
switching #if os(Linux) guarded enum cases, right now you have to write
switch twice:

enum Operation {
  case output(String)
#if os(Linux)
  case syscall(Syscall)
#endif
}
func execute(operation: Operation) {
#if !os(Linux)
   switch operation {
   case .output(let str):
       print(str)
   }
#else
   switch operation {
   case .output(let str):
       print(str)
   case .syscall(let call):
       call.execute()
   }
#endif
}

This is annoying and error prone.
<https://gist.github.com/rintaro/a5a9d9836027d7df7a5326a3a8cf9d89#proposed-solution>Proposed
solution

This proposal allows #if to guard switch case clauses.

func execute(operation: Operation) {
    switch operation {
    case .output(let str):
        print(str)
#if os(Linux)
    case .syscall(let call):
        call.execute()
#endif
    }
}

<https://gist.github.com/rintaro/a5a9d9836027d7df7a5326a3a8cf9d89#detailed-design>Detailed
design

This change shouldn't affect existing #if directives *within* case clauses.
This code should works as expected:

func foo(x: MyEnum) {
    switch x {
    case .some(let str):
        doSomething(str)
#if PRINT_SOME
        print(str)
#endif
    case .other:
        doOther()
    }
}

Only if the next token after #if is case or default, the Parser treat it as
guarding case clauses.

func foo(x: MyEnum) {
    switch x {
    case .some(let str):
        doSomething(str)
#if HAS_OTHER
    case .other:
        doOther()
    }
#endif
}

func foo(x: MyEnum) {
    switch x {
    case .some(let str):
        doSomething(str)
#if HAS_OTHER
    default:
        break
#endif
}

Error cases:

    switch x {
    case .some(let str):
        doSomething(str)
#if HAS_OTHER
    case .other:
        doOther()
#else
        doMore() // error: all statements inside a switch must be
covered by a 'case' or 'default'#endif
    }

    switch x {
    case .some(let str):
        doSomething(str)
#if HAS_OTHER
        doMore()
    case .other:
        doOther() // error: 'case' label can only appear inside a
'switch' statement#else
    }

You can guard multiple cases as long as it is guarding whole clauses:

    switch x {
    case .some(let str):
        doSomething(str)
#if HAS_OTHERS
    case .other:
        doOther()
    case .more:
        doMore()
#else
    }


<https://gist.github.com/rintaro/a5a9d9836027d7df7a5326a3a8cf9d89#source-compatibility>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170510/77b52d6f/attachment.html>


More information about the swift-evolution mailing list