Hacker News new | ask | show | jobs
by foo101 2966 days ago
I don't think "Yoda notation" is good advice. How do you prevent mistakes like the following with Yoda notation?

  if ( level = DEBUGLEVEL )
When both sides of the equality sign are variables, the assignment will succeed. Following Yoda notation provides a false sense of security in this case.

As an experienced programmer I have written if-statements so many times in life that I never ever, even by mistake, type:

  if (a = b)
I always type:

  if (a == b)
by muscle memory. It has become a second nature. Unless of course where I really mean it, like:

  if ((a = b) == c)
5 comments

FWIW I'm pretty sure both the devs who did this and both the other devs who code reviewed it would claim the same thing...

Like other people are saying - the toolchain should have caught this. And it should have, I don't remember how it'd been disabled...

One way to not write any bugs is to not write any code.

If you must write code, errors follow, and “defence in depth” is applicable. Use an editor that serves you well, use compiler flags, use your linter, and consider Yoda Notation, which catches classes of errors, but yes, not every error.

One of the sides is(should be) a CONSTANT. And you can't assign a value to a constant.
Why should one of the sides be a constant? There is plenty of code where both sides are variables.
What about this?

if (env('LOG_LEVEL') = 3) {}

Would throw and everything would be ok. Otherwise, use constants.

Also, lint against assignment in if/while conditions. If you want to assign in those conditions, disable linting for the line and make it explicit.

And if you write f# or Java code?
These kinds of issues are excellent commercials for why the strictness of a language like F# (or OCaml, Haskell, etc), is such a powerful tool for correctness:

1) Outside of initialization, assignment is done with the `<-` operator, so you're only potentially confused in the opposite direction (assignments incorrectly being boolean comparisons).

2) Return types and inputs are strictly validated so an accidental assignment (returning a `void`/`unit` type), would not compile as the function expects a bool.

3) Immutable by default, so even if #1 and #2 were somehow compromised the compiler would still halt and complain that you were trying to write to something unwriteable

Any of the above would terminally prevent compilation, much less hitting a code review or getting into production... Correctness from the ground up prevents whole categories of bugs at the cost of enforcing coding discipline :)

This is why I love F# but if you jump between f# and c# your muscle memory will suffer.
In Java you usually use `.equals()` to test equality, or if your argument is a boolean value:

    if (myVar) {
        //
    }
Instead of `myVar == true/false`.

The accidental assignment is much less common due to the way equality is tested in Java.

Also, `null` comparisons being assigned will fail to compile (assuming var is a String here):

    TestApp.java:6: error: incompatible types: String cannot be converted to boolean
        if (var = null) {
But in Java it’s much easier to do the error of using == instead of equals if you always jump language.
Sure, but that is such a common mistake that all Java IDE's warn you when you try to use == for Strings and normal non-number objects.
For java code, use final so that you have constants.
Note these are only constant pointers. Your data is still mutable if the underlying data structure is mutable, (e.g. HashMap). Haven't used Java in a few years, but I made religious use of final, even in locals and params.
Good point regarding mutable data. But since we were talking about loglevels, I don't think it's a problem there.