Why is Nil coalescing operator Right Associative?
Asked Answered
W

1

5

Shouldn’t it be Left Associative?

I think

let a = b ?? c ?? d

is grouped like

let a = (b ?? c) ?? d

not

let a = b ?? (c ?? d)

But it is declared as a Right Associative. Do I misunderstand or miss something?

Waldron answered 15/10, 2014 at 10:18 Comment(0)
E
8

I think it's an optimization. Left or right association doesn't change the result.

This:

(b ?? c) ?? d

evaluates b ?? c, and its result is used as the left side of x ?? d. So even if b is not null, the coalescing operator is executed 2 times.

In this case instead

b ?? (c ?? d)

if b is not nil, the expression at the right side is not evaluated, hence not executed


Addendum

To prove that, I made a simple test: I (re)defined the nil coalescing operator:

infix operator !!! {
    associativity left
    precedence 110
}

func !!!<T>(optional: T?, defaultValue: @autoclosure () -> T?) -> T? {
    if let value = optional {
        println(optional)
        return value
    }

    let def = defaultValue()
    println(def)
    return def
}

With this test data:

let a: String? = "a"
let b: String? = "b"
let c: String? = "c"

let d = a !!! b !!! c

Using associativity left, this is what's printed to the console:

Optional("a")
Optional("a")

whereas changing the associativity to right, the output is:

Optional("a")

That means when using right associativity the right side of the operator is ignored if the left is not nil.

Electra answered 15/10, 2014 at 10:40 Comment(6)
I think in ```` b ?? (c ?? d) ```` the (c ?? d?) should be evaluated before checking if b is nil because they are in parenthesis. So those expression would be evaluated even though b is not nil but they are not.Waldron
But I can see your point on the evaluation of these expression which is a great point. So does this imply that the Nil Coalescing has a special evaluation rule?Waldron
I don't think it's a special evaluation rule. It works with both left and right associativity, but in the latter case its execution is more optimized. See updated answerElectra
Wow thank you so much. I forgot to considering the @autoclosure. Your example is so great for explain this.Waldron
I used your code snippet and remove @autoclosure, the result is like what I expect.Waldron
+1 Just for completeness I'll mention that we could have f() ?? g() ?? h() where f may throw if g is called first, etc. In this case, order does matter.Principality

© 2022 - 2024 — McMap. All rights reserved.