1

In this code I am looping over all indices in a 3D domain, and printing the "diagonal" part as

for (i, j, k) in {0..9, 0..9, 0..9}
{
    if i == j == k              // (1)
    //if (i == j) && (j == k)   // (2) -> gives expected result
    {
        writeln((i, j, k));
    }
}

My expected result is something like

(0, 0, 0)
(1, 1, 1)
(2, 2, 2)
(3, 3, 3)
(4, 4, 4)
(5, 5, 5)
(6, 6, 6)
(7, 7, 7)
(8, 8, 8)
(9, 9, 9)

which is obtained with Line (2) above. But if I use Line (1), it gives an unexpected result like

(0, 0, 1)
(0, 1, 0)
(0, 2, 0)
...
(9, 7, 0)
(9, 8, 0)
(9, 9, 1)

So I am wondering if I am erroneously using i == j == k? (FYI, the above code is motivated by some Python code like

for i in range(10):
    for j in range(10):
        for k in range(10):

            if i == j == k:
                print( i, j, k )

which gives (0, 0, 0), (1, 1, 1), ...)

2
  • 4
    Perhaps a comparison like i == j == k will be the same as either (i == j) == k or i == (j == k)? In other words, you compare the bool result of one comparison with a non-bool value. Different programming languages do different things. Always read the documentation and learn the language basics, especially when it comes to things like precedence and associativity of operators. Nov 5, 2020 at 3:53
  • @Someprogrammerdude Thanks very much, I think you are right... It looks like i == j == k is interpreted as (i == j) == k (the first comparison is evaluated first, the result of which is converted to 1 or 0, and compared to k). It looks like the behavior is very dependent on languages, so I need to be careful... (I will add a self-answer later.)
    – minibean
    Nov 5, 2020 at 4:51

2 Answers 2

4

Right on, @Someprogrammerdude.

== is a binary operator, it is left-associative. The documentation is here:

https://chapel-lang.org/docs/language/spec/expressions.html#precedence-and-associativity

When comparing the boolean (i==j) with the integer k (in the context of i==j==k), the boolean is implicitly converted to an integer and an integer equality check is performed.

1
  • 1
    Thanks very much! (I tried some more codes, and it seems there are 3 groups of languages, e.g. the "C++-like" group, "make it an error" group, and "python-like group")
    – minibean
    Nov 5, 2020 at 5:57
1

FWIW, these are results that I got from other languages (but my usage of each language may be wrong, so please take it as such...).

C++

#include <iostream>
using namespace std;

int main() {
    int i = 2, j = 2, k = 2;
    cout << (i == j == k) << endl;
}
// => 0 (false), probably by interpreting it as (i == j) == k

Chapel

var i, j, k = 2;
writeln( i == j == k );
// => false (same as C++)

D

import std.stdio;
void main() {
    int i = 2, j = 2, k = 2;
    writeln( i == j == k );
}
// => Error: found == when expecting ) (and some related messages)

Rust

fn main() {
    let i = 2;
    let j = 2;
    let k = 2;
    println!( "{:?}", i == j == k );
}
// => Error
error: chained comparison operators require parentheses
 --> test.rs:6:25
  |
6 |     println!( "{:?}", i == j == k );
  |                         ^^^^^^^^^

error[E0308]: mismatched types
 --> test.rs:6:33
  |
6 |     println!( "{:?}", i == j == k );
  |                                 ^ expected bool, found integer
  |

Scala (here ">" is REPL)

> var i = 2
> var j = 2
> var k = 2
> i == j == k
         ^
  warning: comparing values of types Boolean and Int
           using `==` will always yield false
  res0: Boolean = false

Kotlin

> var i = 2
> var j = 2
> var k = 2
> i == j == k
error: operator '==' cannot be applied to 'Boolean' and 'Int'
i == j == k

Nim

var i = 2
var j = 2
var k = 2
echo( i == j == k )

=> Error: type mismatch: got <bool, int>
but expected one of: 

proc `==`(x, y: bool): bool
  first type mismatch at position: 2
  required type for y: bool
  but expression 'k' is of type: int

expression: i == j == k

Python

> i = 2
> j = 2
> k = 2
> i == j == k
True

Julia

> i = 2
> j = 2
> k = 2
> i == j == k
true

So, apart from Python and Julia (which are dynamically typed so might be a bit different thing), it seems that more lately developed statically typed languages tend to give a warning (or even an error) against the use of i == j == k. So, if Python users may be likely to use Chapel, I guess it might be helpful (for the user) to give some warning (or even an error?) message.

4
  • 1
    That's an interesting proposal, thanks @minibean. It would be trivial to add a == overload between mixed ints and bools that generated a warning in Chapel. It'd be interesting (and also trivial) to check whether it would generate noise for code patterns that we rely on today.
    – Brad
    Nov 5, 2020 at 17:12
  • 1
    With a very quick check, it looks as though we could add such warnings without breaking anything important that is part of our repository.
    – Brad
    Nov 5, 2020 at 21:02
  • @Brad Actually, I was surprised that I did not think it "strange" or "dangerous" to use i == j == k when translating some code from Python to Chapel (where the Python code used this double == things). So I imagined that a similar error pattern may appear for someone else (in future), which could be very tricky to debug because the bug is "silent"... So I appreciate it if it could be considered as a potential issue to be treated (in future).
    – minibean
    Nov 6, 2020 at 0:08
  • Completely agree. If you'd be up for opening an issue on Chapel's GitHub issues page requesting this (either a warning or a re-definition of a == b == c), that would be great and the best way to make sure my experiment doesn't get lost.
    – Brad
    Nov 6, 2020 at 17:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.