Why I cannot do? if let value = x && value == "Fine" {

var x: String? = "Help me"

if let value = x && value == "Fine" {
    print("Good!")
}

Error: Use of unresolved identifier 'Value'

As per Swift operator precedence rule, it reads like this:

if let value = (x && (value == "Fine")) { ... }

Which, as you can see, uses value to set value.

What you want is to check if value is not nil, then check if value == "Fine"

It is done like this in Swift

if let value = x, value == "Fine" {
    ...
}

Or sometimes a more preferable spacing/indentation:

if let value = x,
    value == "Fine" { 
    ...
}
9 Likes

Here's the Precedence rule that Swift uses (I couldn't find the official reference anywhere else).

1 Like

Another way to approach it: if x == "Fine" { ... }.

Because you're checking a specific value, there isn't much value to conditionally binding value. If it's bound, it'll always have the value "Fine". If you need to use that as a value, I think it would be better to just extract it out, use it in your if's predicate, and then in the body.

This works because Swift is implicitly promoting "Fine" into an optional string, which allows for == comparison.

3 Likes

Ah, I remembe now. Thanks!

Just curious, what if I want || instead of &&?

if let value = x || value == "Fine" {

is it possible to compactly express this?

The precedence is, from highest to lowest; ==, &&, ||, =, so the order doesn't change.

Secondly, It wouldn't make sense even if you're doing

(let value = x) || (value == "Fine")

does it?

Also, = has lowest precedence, so whatever you do, it's all part of the assignment.

yes, my code doesn't make sense. sorry. Wasn't thinking :frowning:

I mean to ask:

var x: String? = "Help me"
var y = "foo"

if let value = x && y == "foo" {.  // <=== possible to express this?
    print("Good!")
}

I see what you mean, precedence is done before type checking. So you're essentially writing, as before:

if let value = (x && (y == "foo")) { ... }

Since y and "foo" are String, they can compare, and returns Bool (we have that declared in the standard library somewhere). This is then equivalent to:

if let value = (x && true) { ... }

but the problem is that we don't have String? && Bool operator, or more formally:

func &&(lhs: String?, rhs: Bool) -> ReturnType { ... }

At least, not in standard library. So it'll just be compile error.

As was hinted, you can define operator between 2 types yourself, or even declare a new operator, eg =~=~=, when you find it convenient.

PS

As @AlexanderM said, inside the if block the value is always "Fine" anyway, so you might as well just do if x == "Fine" { ... }

The explanation of precedence is here, and the list of built‐in operators is here.

1 Like

In Swift, an if statement (or a guard statement or a while statement) takes a “condition-list”. The Swift Programming Language gives the grammar for a condition-list:

condition-list → condition | condition , condition-list
condition → expression | availability-condition | case-condition | optional-binding-condition

Of relevance to your question are the condition alternatives “expression” and “optional-binding-condition”:

  • let value = x is an optional-binding-condition.
  • y == "foo" is an expression.

The condition-list grammar shows that you need to separate your conditions with a comma (,), and not anything else (like && or ||). Thus:

if let value = x, y == "foo" { ... }
3 Likes

Not sure if this is your issue, but something to keep in mind is if let and guard let are not boolean operations. This took me an annoyingly long time to incorporate into how I think about these statements :innocent:.

In the C-based-languages was used to if statements always evaluate to a single boolean. That model doesn't really fit what's functionally happening with Optional Binding. See @mayoff's explanation for more details. The way I think about it is if behaves more like a function with arguments, one of which could be a boolean condition, rather than a simple boolean evaluation.

5 Likes