Hacker News new | past | comments | ask | show | jobs | submit login

Somewhat unrelated: Can someone explain the rationale for writing comparisons in the ordering they're using (e.g., 2180 < week)?

I've seen similar before and always thought it seemed error-prone to not write them the way they'd be spoken aloud, but happy to entertain other explanations.




This is probably just me, but I always tend to write a bigger number in the right, so that I can picture a number line in my head.

(Which means I rarely use > and >= operators. It's always < or <=.)

Now, come to think about it, this might have something to do with my native language (Japanese). In Japanese, where the verb always comes at the end of a sentence, you can say "a < b" and "b > a" using the same order and same adjective.

   a < b ... a -than b -toward bigger (a よりも b のほうが 大きい)
   b > a ... b -toward a -than bigger (b のほうが a よりも 大きい)


I've seen style guides recommend that to avoid typos on == that accidentally result in assignment: write "123 == foo" instead of "foo == 123" so that you can't accidentally write "foo = 123".


Surely such code would be caught by some other tool, and isn’t worth the mental overhead to translate it back into the more natural form?


It's not only about not accidentally writing `if (x=0)`.

The `if (0==x)` style also makes it obvious that the check is correct when reviewing/reading code. Sure, a linter might catch this. But this way the reader doesn't need to rely on that. Besides many codebases allow variable assignment as part of conditional/loop expressions, and sometimes sadly it's easier to write code this way than to get a team to use a linter.

Regarding it being unnatural... you get used to it, and especially in C one needs to take care to check the return code the right way (0!=, 0==, -1!=, 0<, !, etc.), whereas the other side of the check is often more straightforward (a function call, a variable etc.), so it's nice to have the constant up front. It takes very little extra space at the front. As a bonus all the constants will visually line up nicely that way.


Both GCC and Clang have -Wparentheses, enabled with -Wall, which will warn on constructs like `if(x=0)`. MSVC also has a warning for this.


"Natural" is both not universal, and re-trainable. `value [op] var` is quite common in many circles, it is natural to many of those coders.


> Surely such code would be caught by some other tool

This technique was invented back in the 1980s, back then compilers have no static analysis capabilities that we take for granted today. I think the reason of keep using it in 2020 is a matter of habit.


It's caught by the compiler since you can't assign to a constant. Why would you need another tool?


Or we can take advantage of our compilers instead of mountains of untested linting cruft.


I can get on board with this, as it scans the same both directions


When working with lots of timeseries information I've found it helpful to always order comparisons so that left-to-right is always increasing, so I would write 2180 < week, or even (not 2180 < week) for the negation of the condition. This becomes almost required when there are multiple values being tested: (a <= 10 && 10 <= b && b <= c) is much easier to read than (a <= 10 && b >= 10 && b <= c). As a perspective, it's more focussed on establishing an invariant of the resulting data than writing a single predicate.


I assume it's a habit formed from guarding against unintentional assignment.

Less so for most comparisons, but for equality, it'll throw an error if you're using the wrong operator instead of having unintended side effects.

week = 2180 will set the week to 2180 in a lot of languages.

2180 = week will always throw an error.

So if I want to compare, it's safer to use the form of 2180 == week because if I forget the second '=', the compiler will tell me before I make bigger problems.


This mistake also requires that the assignment operator has a result (and further, that the result can be silently coerced into a boolean for whatever reason)

In both Rust and Swift, this mistake doesn't compile, their assignment operators don't have a result and so it can't very well be true (or false) ‡

‡ Technically the result of Rust's assignment operators is the empty tuple, which is the closest to "doesn't have a result" in the type system. I don't know about Swift.


As far as I'm aware, only C and C++ a use for Yoda conditions have.


Big the C family is. Copied to many languages its quirks have been.


That is a stellar point, thank you for this.


Even more unrelated, but equally pedantic, I've always thought it's weird when people write "null != val" instead of "val != null" for the same reason.

When said out loud, "null is not val" just feels wrong.


Comes from the null==val idiom, and that comes from avoiding the popular "if (val=null)" bug in C/C++.

Sure, we could just admit that assignments in conditions are a permanently stupid idea. Instead, an entire industry backwards the conditions wrote.


I find initializing condtions like `if(Type variable = ...)` to be very nice in C++ to avoid excessive nesting while still keeping the variable scoped to the block. Of course, I also enable -Wparentheses for things like `if(val=null)`, which you get e.g. when using -Wall with both GCC and Clang.


Isn't that just Yoda notation? https://en.wikipedia.org/wiki/Yoda_conditions


In PowerShell you'll get a linter warning because things like (look at the -):

if (@() -eq $null) { 'true' }else { 'false' } # false

if (@() -ne $null) { 'true' }else { 'false' } # false


And there also exist expressions for the left-hand side that make both expressions truthy, like [0]:

  $v = $null, $null, 1

  ($v -eq $null) -and ($v -ne $null) # True
In both these cases, this is caused by the language having built-in binary operators for when the left-hand side expression is a collection type that perform the operation elementwise and return an array.

Interestingly, it seems like PowerShell's operator overload resolution in general depends entirely on the type of the LHS. I say 'seems' because I couldn't find any sort of language specification when I looked into it a while ago like what C# and VB.NET have, and testing seemed to confirm that this was the case. Now, searching the PowerShell Core source, it seems from [1] that this is indeed the implementation.

This contrasts with C# [2] and VB.NET [3], where binary operator overload resolution is treated as if the candidate operator implementations were a two-parameter method group, making the resolution process 'commutative' (though not always commutative in practice as the operators themselves can still have different LHS and RHS types {Edit: example from the CLR [4]: +(Point, Size) but not +(Size, Point)}).

[0] https://blog.iisreset.me/schrodingers-argumentlist/

[1] https://github.com/PowerShell/PowerShell/blob/master/src/Sys...

[2] https://docs.microsoft.com/en-us/dotnet/csharp/language-refe...

[3] https://docs.microsoft.com/en-us/dotnet/visual-basic/referen...

[4] https://source.dot.net/#System.Drawing.Primitives/System/Dra...


Can't speak for that particular example, but sometimes you might write a < x so that later you can naturally && it with x < b.


> Can someone explain the rationale for writing comparisons in the ordering they're using (e.g., 2180 < week)?

https://en.wikipedia.org/wiki/Yoda_conditions

> it seemed error-prone to not write them the way they'd be spoken aloud

It is written the way it'd be spoken aloud. If you're not speaking it that way then you need to change the way you think. Programming is another language after all.


I don't know about you, but "week is greater than 2180" sounds more natural than "2180 is less than week"


> I don't know about you, but "week is greater than 2180" sounds more natural than "2180 is less than week"

To you perhaps. To me, I think "if I put both sides on the number line, which way is being questioned? and is that question answered true or false?"

And therefore I almost always do an equals or less-than comparison because that's how I think about the number line: 0 in the center with negatives on the left and positives on the right.

So `if (week < 2048)` is just as valid and easy to think about as `if (!(2048 <= week))`. But then `if (!(2048 <= week))` provides an additional guarantee: that I won't accidentally assign to `week`.




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: