Associativity of && and || operator


#1

Hello all,

Why the associativity of Logical{Conjunction,Disjunction}Precedence is "left
"?

If you write: A && B && C, it's grouped as (A && B) && C.
This means that the && function is *always* called twice: (&&)((&&)(A, B),
C).
I feel "right" associativity is more natural: (&&)(A, (&&)(B, C)),
because the && function is called only once if A is false.

I know that redundant && calls are optimized away in most cases.
I also know C and C++ standard says: "The && operator groups
left-to-right", and most programming languages follow that.

But why not "right" associativity?
What is the difference between logical operators and ?? operator that has "
right" associativity?


(Saagar Jha) #2

Left associativity is most likely just a holdover from the C family–not conforming with it would break expectations for programmers coming from these languages. And as you mentioned, the compiler will short-circuit the condition and stop evaluating as soon as it encounters a false condition, so there’s no measurable benefit.

Saagar Jha

···

On Feb 17, 2017, at 12:54 AM, rintaro ishizaki via swift-users <swift-users@swift.org> wrote:

Hello all,

Why the associativity of Logical{Conjunction,Disjunction}Precedence is "left"?

If you write: A && B && C, it's grouped as (A && B) && C.
This means that the && function is always called twice: (&&)((&&)(A, B), C).
I feel "right" associativity is more natural: (&&)(A, (&&)(B, C)),
because the && function is called only once if A is false.

I know that redundant && calls are optimized away in most cases.
I also know C and C++ standard says: "The && operator groups left-to-right", and most programming languages follow that.

But why not "right" associativity?
What is the difference between logical operators and ?? operator that has "right" associativity?

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Jordan Rose) #3

Remember too that in Swift the operator is decoupled from its implementation. Plenty of people are using && for things like constraint or predicate DSLs, where it doesn't short-circuit. Of course, a non-associative version of && would be quite surprising, so even a custom implementation probably shouldn't rely on the left-associativity.

There's one other reason to prefer this way, though, and that's complexity in the AST. Recall that the RHS of the standard && (and ||, and ??) is an auto-closure—Swift's way to avoid the eager evaluation of the argument. Right-associativity would result in heavily-nested autoclosures, and even though they'll all be flattened as part of compilation, the AST representation still has to model them that way. So purely from a compiler-implementation perspective left-associativity has a small edge.

I think you're right that we should have picked right-associativity anyway, but at this point I'm not sure it's worth changing it.

Jordan

···

On Feb 17, 2017, at 01:03, Saagar Jha via swift-users <swift-users@swift.org> wrote:

Left associativity is most likely just a holdover from the C family–not conforming with it would break expectations for programmers coming from these languages. And as you mentioned, the compiler will short-circuit the condition and stop evaluating as soon as it encounters a false condition, so there’s no measurable benefit.

Saagar Jha

On Feb 17, 2017, at 12:54 AM, rintaro ishizaki via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

Hello all,

Why the associativity of Logical{Conjunction,Disjunction}Precedence is "left"?

If you write: A && B && C, it's grouped as (A && B) && C.
This means that the && function is always called twice: (&&)((&&)(A, B), C).
I feel "right" associativity is more natural: (&&)(A, (&&)(B, C)),
because the && function is called only once if A is false.

I know that redundant && calls are optimized away in most cases.
I also know C and C++ standard says: "The && operator groups left-to-right", and most programming languages follow that.

But why not "right" associativity?
What is the difference between logical operators and ?? operator that has "right" associativity?

_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Howard Lovatt) #4

To me it would be surprising if && grouped differently than * or &; since
it is closely associated with boolean-and, which in turn is the equivalent
operation to multiply in Boolean logic.

···

On Fri, 17 Feb 2017 at 7:56 pm, rintaro ishizaki via swift-users < swift-users@swift.org> wrote:

Hello all,

Why the associativity of Logical{Conjunction,Disjunction}Precedence is "
left"?

If you write: A && B && C, it's grouped as (A && B) && C.
This means that the && function is *always* called twice: (&&)((&&)(A,
B), C).
I feel "right" associativity is more natural: (&&)(A, (&&)(B, C)),
because the && function is called only once if A is false.

I know that redundant && calls are optimized away in most cases.
I also know C and C++ standard says: "The && operator groups
left-to-right", and most programming languages follow that.

But why not "right" associativity?
What is the difference between logical operators and ?? operator that has
"right" associativity?

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

--
-- Howard.


#5

Remember too that in Swift the *operator* is decoupled from its
*implementation.* Plenty of people are using && for things like
constraint or predicate DSLs, where it doesn't short-circuit.

I think I'm convinced. :slight_smile:
If you want to use && or || as an accumulator, left-associativity makes
more sense.

func || (condition: Condition, val: String) -> Condition {
  return condition.addingOr(string: val)
}
condition = condition || ">= 42" || "< 12"

Thank you guys!

···

2017-02-21 3:16 GMT+09:00 Jordan Rose <jordan_rose@apple.com>:

Remember too that in Swift the *operator* is decoupled from its
*implementation.* Plenty of people are using && for things like
constraint or predicate DSLs, where it doesn't short-circuit. Of course, a
non-associative version of && would be quite surprising, so even a custom
implementation probably shouldn't rely on the left-associativity.

There's one other reason to prefer this way, though, and that's complexity
in the AST. Recall that the RHS of the standard && (and ||, and ??) is an
auto-closure—Swift's way to avoid the eager evaluation of the argument.
Right-associativity would result in heavily-nested autoclosures, and even
though they'll all be flattened as part of compilation, the AST
representation still has to model them that way. So purely from a
compiler-implementation perspective left-associativity has a small edge.

I think you're right that we should have picked right-associativity
anyway, but at this point I'm not sure it's worth changing it.

Jordan

On Feb 17, 2017, at 01:03, Saagar Jha via swift-users < > swift-users@swift.org> wrote:

Left associativity is most likely just a holdover from the C family–not
conforming with it would break expectations for programmers coming from
these languages. And as you mentioned, the compiler will short-circuit the
condition and stop evaluating as soon as it encounters a false condition,
so there’s no measurable benefit.

Saagar Jha

On Feb 17, 2017, at 12:54 AM, rintaro ishizaki via swift-users < > swift-users@swift.org> wrote:

Hello all,

Why the associativity of Logical{Conjunction,Disjunction}Precedence is "
left"?

If you write: A && B && C, it's grouped as (A && B) && C.
This means that the && function is *always* called twice: (&&)((&&)(A,
B), C).
I feel "right" associativity is more natural: (&&)(A, (&&)(B, C)),
because the && function is called only once if A is false.

I know that redundant && calls are optimized away in most cases.
I also know C and C++ standard says: "The && operator groups
left-to-right", and most programming languages follow that.

But why not "right" associativity?
What is the difference between logical operators and ?? operator that has
"right" associativity?

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users