Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Warn on useless comparisons #4205

Open
Papipo opened this issue Jan 31, 2025 · 12 comments · May be fixed by #4213
Open

Warn on useless comparisons #4205

Papipo opened this issue Jan 31, 2025 · 12 comments · May be fixed by #4213

Comments

@Papipo
Copy link

Papipo commented Jan 31, 2025

Hi there,

I had a typo in some code and I was comparing a variable with itself, like group_id != group_id. One of those was supposed to be group.id, and I think it's a common typo.

The idea is that the compiler is able to detect such comparisons and warn about them, since they will always evaluate to the same and are completely useless.

Thanks 🙇🏽

@Ramkarthik
Copy link
Contributor

@lpil and @Papipo If we are doing this, would something like the below work?

Variable:

warning: Same operand on either side of the equality operator
  ┌─ /gleam/test/equality/src/equality.gleam:8:8
  │
8 │   case greeting != greeting {
  │        ^^^^^^^^^^^^^^^^^^^^ This will always be false

Field access:

warning: Same operand on either side of the equality operator
  ┌─ /gleam/test/equality/src/equality.gleam:8:8
  │
8 │   case wibble.age == wibble.age {
  │        ^^^^^^^^^^^^^^^^^^^^^^^^ This will always be true

Would we want to implement this for anything else apart from variables and field access?

@giacomocavalieri
Copy link
Member

giacomocavalieri commented Feb 1, 2025

Just field access, module selects, literal values and variables I'd say. @Ramkarthik are you planning to work on this?

@Ramkarthik
Copy link
Contributor

@giacomocavalieri I have implemented this for field access and variables to emit the warning mentioned in my previous comment. I can look into implementing it for module selects and literal values as well. I'll give it a try today.

I'm assuming we would also want this for gt, gte, 'lt, and lte` for Int and Float.

@giacomocavalieri
Copy link
Member

Great thank you!! Not sure we also want it for those operators, I'd just start with equality checks 👍

@lpil
Copy link
Member

lpil commented Feb 1, 2025

Hello! Good idea @Papipo, thank you.

@Ramkarthik @giacomocavalieri The goal is to warn for useless comparisons generally, not for equality checks with the same value specifically.

These should emit a warning saying they always evaluate to true:

1 < 2
3 == 3
1 != 2
1.5 >. 1.1
xyz == xyz
wibble.wobble == wibble.wobble

These should emit a warning saying they always evaluate to false:

1 > 2
3 != 3
1 == 2
1.5 <. 1.1

@Ramkarthik
Copy link
Contributor

@lpil Got it, that makes sense. I can work on this on the same PR (or a new one) if you'd like, or leave it open for someone/future. Would like to know your opinion on what the warning title should be. The hint can be "This is always [true | false]" depending on the condition.

@lpil
Copy link
Member

lpil commented Feb 4, 2025

Perhaps "redundant comparison"?

@lydell
Copy link

lydell commented Feb 7, 2025

Note that saying that x == x is always True isn’t necessarily … true. Because of Nan.

import gleam/io

pub fn main() {
  // Infinity divided by infinity is NaN (this is mentioned at https://tour.gleam.run/basics/floats/).
  let x = 2.0e308 /. 2.0e308
  // Prints False (!) in JS (NaN is never equal to NaN).
  // I'm not sure how it behaves in Erlang.
  io.debug(x == x)
  io.debug(x) // This prints NaN.0
}

I guess that’s quite the edge case though, but leaving a note here in case it helps you with the design for this feature.

@lpil
Copy link
Member

lpil commented Feb 8, 2025

Gleam doesn't have a NaN! If you want to check for external values which don't obey Gleam's equality rules then you should use external functions.

@lydell
Copy link

lydell commented Feb 8, 2025

Gleam doesn't have a NaN!

I’m confused, the Tour page I linked to says:

Under the JavaScript runtime, exceeding the maximum (or minimum) representable value for a floating point value will result in Infinity (or -Infinity). Should you try to divide two infinities you will get NaN as a result.

I tested that, and it’s true. You can try it by pasting my code above in the tour page.

@lpil
Copy link
Member

lpil commented Feb 8, 2025

That's a detail of the target platform. Gleam itself does not have NaN.

@Papipo
Copy link
Author

Papipo commented Feb 10, 2025

Perhaps "redundant comparison"?

Or "ineffective comparison", since it reflects that the code is doing nothing in practice?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants