Why Can't I Use a Tuple Constant as a Case in a Switch Statement

Why can't I use a tuple constant as a case in a switch statement

You could implement the ~= operator for the mydTuple type like this:

func ~=(a: mdyTuple, b: mdyTuple) -> Bool {
return a.month ~= b.month && a.year ~= b.year && a.day ~= b.day
}

That worked for me in a Playground... Now, this code

switch someday {
case joesBirthday:
println("one")
default:
println("two")
}

prints "one".

This is the operator's definition:

infix operator ~= {
associativity none
precedence 130
}

and is implemented for the following:

/// Returns `true` iff `pattern` contains `value`
func ~=<I : IntervalType>(pattern: I, value: I.Bound) -> Bool
func ~=<T>(lhs: _OptionalNilComparisonType, rhs: T?) -> Bool
func ~=<T : Equatable>(a: T, b: T) -> Bool
func ~=<I : ForwardIndexType where I : Comparable>(pattern: Range<I>, value: I) -> Bool

Swift switch statement on a tuple of optional booleans

There are a bunch of ways to do this, but to fix the syntax of what you are trying to do literally, you need to explicitly unbox the Optional, either by matching against .Some(false), or unwrapping it with ! (which I think is kind of weird, as you'll see)

var dict = Dictionary<String,Bool>()
dict["a"] = true
dict["c"] = false

func matchOneOrTheOtherWithOptionals(a: Bool?, b: Bool?) -> String {
switch (a, b) {
case (.Some(true), let b) where b == .None || !b!: // gross
return "a was true, but b was None or false"
case (let a, .Some(true)) where a == .None || a == .Some(false):
return "a was None or false and b was true"
default:
return "They both had a value, or they were both missing a value"
}
}

matchOneOrTheOtherWithOptionals(true, .None) // "a was true, but b was None or false"
matchOneOrTheOtherWithOptionals(true, false) // "a was true, but b was None or false"
matchOneOrTheOtherWithOptionals(.None, true) // "a was None or false and b was true"
matchOneOrTheOtherWithOptionals(false, true) // "a was None or false and b was true"

matchOneOrTheOtherWithOptionals(false, false) // "They both had a value, or they were both missing a value"
matchOneOrTheOtherWithOptionals(true, true) // "They both had a value, or they were both missing a value"
matchOneOrTheOtherWithOptionals(.None, .None) // "They both had a value, or they were both missing a value"

You could also try the following:

func noneToFalse(bool: Bool?) -> Bool {
if let b = bool {
return b
} else {
return false
}
}

func matchOneOrTheOther(a: Bool, b: Bool) -> String {
switch (a, b) {
case (true, false):
return "a is true, b was false or None"
case (false, true):
return "a was false/None, b was true"
default:
return "both were true, or both were false/None"
}
}

matchOneOrTheOther(noneToFalse(dict["a"]), noneToFalse(dict["b"]))

Here's a gist of the Playground I used while writing this answer: https://gist.github.com/bgrace/b8928792760159ca58a1

Swift tuple switch case : pattern of type cannot match values of type

Solution 1

let ABOUTTROVPROTECTIONCELL = (section: 1, row: 0)
let cellIdentifier = (section: indexPath.section, row: indexPath.row)

switch cellIdentifier {
case (ABOUTTROVPROTECTIONCELL.section, ABOUTTROVPROTECTIONCELL.row):
print("here")
default:
print("bleh")
}

Solution 2

Just use IndexPath struct and its initializer for creating ABOUTTROVPROTECTIONCELL

let ABOUTTROVPROTECTIONCELL = IndexPath(row: 0, section: 1)
let cellIdentifier = indexPath // Not necessary, you can just use indexPath instead

switch cellIdentifier {
case ABOUTTROVPROTECTIONCELL:
print("here")
default:
print("bleh")
}

Solution 3

Implement ~= func for your tuple:

typealias IndexPathTuple = (section: Int, row: Int)
func ~=(a: IndexPathTuple, b: IndexPathTuple) -> Bool {
return a.section ~= b.section && a.row ~= b.row
}

let ABOUTTROVPROTECTIONCELL = (section: 1, row: 0)
let cellIdentifier = (section: indexPath.section, row: indexPath.row)

switch cellIdentifier {
case ABOUTTROVPROTECTIONCELL:
print("here")
default:
print("bleh")
}

case (let name, let x)

A tuple is just a variable that carries more than one value. In your example the tuple is of the type (String, Int) because that's how you first defined it.

Like when you do let name = "Matt" this is just doing that except with an Int alongside the string.

The switch is then then checking that tuple based on the pattern matching.

The (let name, let x) is just taking the values from that tuple and inserting them into the variables named name and x so that they can be used. Without this you would not be able to print the name or age in the code.

If you didn't care about the name you could do...

case (_, let x):
print("This person is \(x) years old")

You can't print the name here because you haven't put it into a variable name.

You could also do case (let dog, let z):. This would work and now the variable dog would be a String with the value "Matt". Except it doesn't really make sense to do this because the value is a name be not a dog. :-)

If you had made your first line as...

let tuple = ("Oliver", 33)

Then the name variable would be "Oliver" and the X would be 33.

Syntax for expanding a tuple used in an enum when using a switch statement

In addition to your Update: answer:

case .FirstCase(output: let (someString, someInt)):

and

case let .FirstCase(output: (someString, someInt)):  // thanks @MartinR

work as well.

By having the output: label in your enum case, you have created a named tuple of one value containing a named tuple of two values. If you don't specify output: in the switch, Swift is going to attempt to match the outer tuple with the tuple you supply and the count of the items doesn't match.

Providing the output: label in the pattern allows Swift to know that you are talking about the inner tuple, and it then works.

If you feel output: is pointless, why include it in your enum definition at all?

Why is 'case' inside a switch statement negative indented?

Well, I would guess that the break statement belongs to the "section" in the case clause. And as any other statement, it is indented relative to the case. As for the case relative to switch - well I don't know.

But I'm completely with you - and formatting is a matter of personal preference anyway. Since the formatting rules in Xcode are not explicitly defined - it cannot be a bug ;)

FWIW, I prefere this style

switch x {
case 1:
// do something
break
case 2:
// do something else
break
default:
// default
break
}

Getting Binary operator ~= cannot be applied to two (Int, Int) operands in Swift switch statement with (Int, Int) tuple cases

Do this.

  switch (indexPath.section, indexPath.row) {
case (IndexPath.Gender.tuple.0, IndexPath.Gender.tuple.1):
// Do something.

case (IndexPath.Weight.tuple.0, IndexPath.Weight.tuple.1):
// Do something.

case (IndexPath.EmergencyContact.tuple.0, IndexPath.EmergencyContact.tuple.1):
// Do something.

default:
break;

}

What does constant binding in switch statements actually do?

From your quote from the Swift documentation:

... can then be referenced in a corresponding where clause and throughout
the rest of the code within the scope of the case.

So in the first case

case let (x,y) where x == y:
print("hello")

greeting (which is the tuple (1, 10)) is matched against the
pattern

let (x,y) where x == y

and if it matches, x is bound to the first tuple element
and y to the second.

This binding is restricted to the scope of the first case,
and cannot be used in the second or other cases.

To make your code compile, add another let binding for the second
case:

switch greeting {

case let (x,y) where x == y:
print("\(x) is equal to \(y)")

case let (x,y) where x < y:
print("\(x) is less than \(y)")

default:
print("No match")
}


Related Topics



Leave a reply



Submit