Compound Switch Cases: May We Have a Single Common Value Binding for Compound Enum Cases That Have the Same Type of Associated Value

Compound switch cases: may we have a single common value binding for compound enum cases that have the same type of associated value?

No, this is not possible; in the value binding examples above, x must be bound in every pattern, and this must hold separately for every pattern in the compound cases.

Quoting the Language Guide - Control Flow [emphasis mine]

Compound cases can also include value bindings. All of the patterns of
a compound case have to include the same set of value bindings, and
each binding has to get a value of the same type from all of the
patterns in the compound case
. This ensures that, no matter which part
of the compound case matched, the code in the body of the case can
always access a value for the bindings
and that the value always has
the same type.

I we try to omit the binding in one of the patterns in the compound example above, we are given quite an self-explanatory error message on the subject:

func foo(_ foo: Foo) -> Int {
switch foo {
case .bar(_), .baz(let x), .bax(let x): return x
case .fox: return 0
}
}
error: 'x' must be bound in every pattern

This holds even if we don't use x in the body that follows

func foo(_ foo: Foo) -> Int {
switch foo {
case .bar(_), .baz(let x), .bax(let x): return 0
case .fox: return 0
}
} // same error

Is it possible to write compound switch case between enum associated value conditional and another enum case?

You don't need a where-clause to match .cloudy(coverage: 0), just

case .cloudy(coverage: 0), .sunny: 
print("☀️")

Another option is to use fallthrough, for example

case .cloudy(let coverage) where coverage < 10:
fallthrough
case .sunny:
print("☀️")

Unwrapping associated value for all cases in switch

Try this in Playground.

enum RowType {
case single(_ content: [Any])
case double(_ content: [Any])
case triple(_ content: [Any])
case noVal

var associatedValue: Any? {
get {
let mirror = Mirror(reflecting: self)
if let associated = mirror.children.first {
return associated.value
}
print("WARNING: Enum option of \(self) does not have an associated value")
return nil
}
}
}

let row : RowType = .double([1,2,3])
let rowNoVal : RowType = .noVal
row.associatedValue
rowNoVal.associatedValue

Binding to an associated value of an enum

You can extend your enumeration and add a text property with a getter and a setter:

extension Choice {
var text: String {
get {
switch self {
case let .one(string): return string
case let .two(string): return string
}
}
set {
switch self {
case .one: self = .one(newValue)
case .two: self = .two(newValue)
}
}
}
}

Then you can simply pass the text property:

TextField("", text: $choice.text) 

Single-element parethesized expressions/tuples vs common use of parentheses

From Types in the Swift book:

If there is only one element inside the parentheses, the type is
simply the type of that element. For example, the type of (Int) is
Int, not (Int).

So the type of (2) or (2+4) is simply Int, and the * in (2+4)*5 is
just integer multiplication.

Swift - Multiple Switch Cases

how about :

struct Object{
var type = 1
}

let lowType = min(object1.type,object2.type)
let highType = max(object1.type,object2.type)
switch( lowType, highType )
{
case (1,1):
doSome()
case (1,2):
doSome2()
case (1,3):
doSome3()
...
// you will only need to specify the combinations where the first
// type is less or equal to the other.
}

If you will be doing this often, you could define a minMax function to further reduce the amount of code needed each time:

func minMax<T:Comparable>(_ a:T, _ b:T) ->(T,T) 
{ return a<b ? (a,b) : (b,a) }

switch minMax(object1.type,object2.type)
{
case (1,1):
doSome()
case (1,2):
doSome2()
...

note that you can also put each inverted pair in its case statement:

switch(object1.type,object2.type)
{
case (1,1):
doSome()
case (1,2),(2,1):
doSome2()
case (1,3),(3,1):
doSome3()
...
}

[UPDATE]

If you have more than two values to compare in a "permutation insensitive" fashion, you could expand on the minMax() idea by creating variants with more values:

func minToMax<T:Comparable>(_ a:T, _ b:T) -> (T,T) 
{ return a<b ? (a,b) : (b,a) }

func minToMax<T:Comparable>(_ a:T, _ b:T, _ c:T) -> (T,T,T)
{ return { ($0[0],$0[1],$0[2]) }([a,b,c].sorted()) }

func minToMax<T:Comparable>(_ a:T, _ b:T, _ c:T, _ d:T) -> (T,T,T,T)
{ return { ($0[0],$0[1],$0[2],$0[3]) }([a,b,c,d].sorted()) }

switch minToMax(object1.type,object2.type,object3.type)
{
case (1,2,3) : doSome1() // permutations of 1,2,3
case (1,2,4) : doSome2() // permutations of 1,2,4
case (1,2,_) : doSome3() // permutations of 1,2,anything else
case (1,5...6,10) : doSome4() // more elaborate permutations
...
}

}

Using Switch Statements in Swift - Value binding INSIDE the parentheses vs outside?

Case 1 is more concise, and better suited for the general case.

Case 2 is more granular. Consider this case:

switch myNumbers {
case (let x, var y):
// x is a constant, y is mutable.
print("the value of x is \(x)")
default:
print("n/a")
}

.net core switch expression incrementing with wrong value

Remember that the compound assignment operator a += b is the same as a = a + b (except that a is evaluated only once), see §7.17.2 of the spec.

Here's a slightly simpler example which doesn't use a switch, and has the same effect:

int j = 2;

int A()
{
j = 10;
return 0;
}

j = j + A();

If you don't want to think in terms of local functions, you can also write this as a class:

class C
{
private int j;

public void Test()
{
j = 2;
j = j + A();
}

private int A()
{
j = 10;
return 0;
}
}

The compiler will:

  1. Start by evaluating j + A():

    1. Push the current value of j, which is 2, onto the stack
    2. Call A(), which sets j to 10 and returns 0
    3. Push the return value of A(), which is 0, onto the stack
    4. Add together the two values on the stack: 2 + 0
  2. Assign this value to j

If you write the assignment the other way around, as j = A() + j, then its final value is 10. If you follow the same sequence of steps as above, you'll see why.


This general approach -- changing a variable as a side-effect of an expression which also changes that variable -- is a bad idea. It leads to very hard-to-understand code.

Switch statement in Swift

The usual rules for the FizzBuzz game
are to replace every multiple of 3 by "Fizz", every multiple of 5 by "Buzz", and
every multiple of both 3 and 5 by "FizzBuzz".

This can be done with a switch statement on the tuple (i % 3, i % 5).
Note that _ means "any value":

for i in 1 ... 100 {
switch (i % 3, i % 5) {
case (0, 0):
print("FizzBuzz")
case (0, _):
print("Fizz")
case (_, 0):
print("Buzz")
default:
print(i)
}
}


Related Topics



Leave a reply



Submit