Question regarding syntax (unwrapping)

Hi,

I was playing with ChatGPT and it gave me the code below:

var johnny = (name: "Johnny", lastName: "Bravo")

let mirror = Mirror(reflecting: johnny)
for child in mirror.children {
    if let label = child.label, label == "name" {
        print(label) // prints out "name"
    }
}

I have never seen this kind of syntax yet:
(talking about the , + condition)

child.label, label == "name"

Is there a name for this?
I have also tried something like this:

child.label where label == "name"

Which doesn't work, I'm not sure what the difference is.
Sorry for poorly phrased question. :innocent:

If and guard accept a list of conditions separated by ‘,’. Those conditions can be pattern matching, unwrapping or a Boolean. Here you are first unwrapping then testing if the value is true. You can also write
if let someBool && someBool like you would in other languages.
Both ways test the condition in order and short circuit on the first invalid one.

2 Likes

It's called "condition list" according to Swift grammar:

4 Likes

You can use a where clause, but you have to set up all the variable names beforehand. E.g.

for case let label? in mirror.children.map(\.label) where label == "name" {
for label in mirror.children.lazy.compactMap(\.label) where label == "name" {
4 Likes

That if statement is equivalent to this:

// If `child.label` contains a value, unwrap the value 
// and assign it to the local variable `label`, then compare
if let label = child.label {
   if label == "name" {
        print (label) // prints out "name"
   }
}
2 Likes

Or, if you can't get enough of where

switch child.label {
case let label? where label == "name":
  print(label)
default:
  break
}

Really though, there's only going to be at most one child with the label "name", so you should break out of the loop at that point:

for child in mirror.children {
  if let label = child.label, label == "name" {
    print(label) // prints out "name"
    break
  }
}

break in a switch statement is more complicated, requiring a label to refer to outer scope:

loop: for child in mirror.children {
  switch child.label {
  case let label? where label == "name":
    print(label)
    break loop
  default:
    break
  }
}

I find it pretty confusing that we use where or a comma depending on whether using switch or not. I guess it's because more commas introduce more conditions or bindings outside a switch, and more cases inside one (requiring && instead of commas). The asymmetry still looks weird for the most common simplest cases.

if case let label? = child.label, label == "name", true, case false = true { }
for child in mirror.children {
  switch child.label {
  case let label? where label == "name",
      .some(let label) where true == false && false == true:
    print(label)
  case _:
    break
  }
}
2 Likes