Readit News logoReadit News
jedisct1 · 7 years ago
All linters and C compilers emit a warning when an assignment is made in a condition.

There are zero reasons to use that ugly and unnatural Yoda notation in 2019.

wruza · 7 years ago

  if (systemcall(“some string”, expression_argument(args), SC_MODE_1 | SC_MODE_DEFAULT) != 0)
  if (0 != systemcall(“some string”, expression_argument(args), SC_MODE_1 | SC_MODE_DEFAULT))
One may find it easier to read/navigate flow control in C code that returns status codes, when these codes are stated beforehand. When there are series of long lines and a mix of 0==success and 0==false, it is easy to get lost, at least in my experience.

T-hawk · 7 years ago
I'd break this up by lines, every time.

  int result = systemcall(“some string”, expression_argument(args), SC_MODE_1 | SC_MODE_DEFAULT))
  if (result != 0)
Separation of concerns. Each line does one thing. Making a system call and branching on its result are two separate tasks.

admax88q · 7 years ago
Yeah but that's also just a ridiculously long line which will be hard to read regardless ;)
johnfactorial · 7 years ago
Furthermore, when we have a problem, if our solution is to have human beings simply remember to do it a different way, we then have two problems.
muench · 7 years ago
I find this quote very powerful. I'm thinking I could re-use it. Is it yours or if it's sourced from somewhere could you share the source?

Deleted Comment

beatgammit · 7 years ago
I think this is reasonable readable:

    while ((status = systemcall(...)) != SUCCESS) {
        do something with status;
    }
Leave a comment there explaining the assignment.

Likewise:

    if ((status = systemcall(...)) != SUCCESS) goto error;
Or something like that. I don't understand the hate, just make sure it's obvious what you're doing.

stochastic_monk · 7 years ago
It’s traditional to build these kinds of loops in C, e.g.:

    int c;
    while((c = getopt(argc, argv, argstr)) >= 0) {...}
I’d say it’s acceptable, and Python is adding syntax so it can mix assignments and checks.

08-15 · 7 years ago
> Leave a comment there explaining the assignment.

Please don't. This is a perfectly understandable idiom in C. Don't explain the language in your comments; that's the job of a text book, which should be read by anyone before they read your code.

marcosdumay · 7 years ago
That's perfectly fine and arguably even better than the alternatives. The `a = b = c = 0;` format is also good.

But enabling it on the language level brings a large amount of risk and complexity just for what amounts to a micro-optimization.

Sahhaese · 7 years ago
This would achieve the same but is far more readable:

   while(status != SUCCESS) {
      status = syscall(...);
      // do something with status
   }

emilfihlman · 7 years ago
Pretty harsh. Imho it's not ugly nor unnatural, just different.

It also reduces time in debugging as you catch it immediately.

weberc2 · 7 years ago
Which is great if your project treats warnings as errors. Not sure how common this is though since every time I compile a C program it’s just pages and pages of warnings.
emilfihlman · 7 years ago
Exactly. All code I write must pass -Wall -Werror -Wextra and there's always a debugging phase once you have written the code since there are syntax errors and whatnot, a lot.
roland35 · 7 years ago
This is true, but sadly warnings can be ignored! At my last job we enforced -Wall so we had no warnings on pull requests to prevent this though.
ur-whale · 7 years ago
A useful aspect of yoda notation is that it often makes an equality test easier to read because the constant is shorter than the expression it is tested against, and the == sign comes right away, not buried far away in the line.

It's my favourite way of writing if statements.

codegladiator · 7 years ago
Not all programming languages !

Deleted Comment

Deleted Comment

saw-lau · 7 years ago
I'm so glad somebody else thinks this! I've always hated that style of notation.
na85 · 7 years ago
Do compilers for other languages emit the same warning? Because there are fewer and fewer reasons to use C in 2019 as well.
shultays · 7 years ago
Not all languages allows chained assignment (a=b=c) like c++ does, which is why we have this problem (and probably does not automatically cast them to bool either)
kemiller2002 · 7 years ago
I know I'm in the minority, but I honestly never really understood why people get so up in arms about this. People keep saying it's so difficult to read, and I just don't understand why. I know that linters and such can catch this most of the time, but a lot of places I've seen don't use them. (I don't know why, that's a whole other discussion.) It just seems to me that it's something that keeps you from wasting time on silly mistakes should be common place. I really don't understand.
carapace · 7 years ago
You must be young, friend. The holy wars that used to rage over just where to put curly brackets...

(And then Python came along and was like, "U wot mate?", and there were had little wars over "syntactically-significant indentation" and tabs vs. spaces, and how many spaces... And on, and on...)

kemiller2002 · 7 years ago
Oh no, I'm not young. I just find this particular argument makes less sense than all the other types of arguments like this. Bracket placement in some languages is necessary to not have unintended effect. Tabs vs spaces can cause problems with certain ides/editors. I can somewhat understand most justifications as to why people have a certain reason for formatting code in their particular way. You want me to indent 3 spaces instead of 2 in Delphi, because that's the way you've done it, fine. I don't care. But this particular one, I don't get it. I never have. The amount of time that this one particular trick saved me in terms of time and frustration is huge. When you spend 45 minutes tracking down a problem because you assigned 5 (or something) to variable by accident, it almost always leads to a mouse throwing event. When someone comes back and says that seeing 42 == x is too difficult to read even though it can save countless hours, I just don't understand. (not every project has the benefit of having a linter or a compiler that will catch things like this.)
plopz · 7 years ago
Just wait until people realize proportional fonts are actually easier to read than mono-spaced fonts.
lugg · 7 years ago
Code is for humans. If your language lets you make silly mistakes maybe it needs to stop doing that. Why can I assign during a branch? It's unnecessary.
canacrypto · 7 years ago
I've found it's better to write normal conditions that are easier to read and leave it to your linter to catch unintended assignments.
thomasahle · 7 years ago
Are they really easier to read though? A lot of the time which variable being tested is obvious, so it makes sense to put the important information - the value - first.
jonny_eh · 7 years ago
> so it makes sense to put the important information

Both sides of the equality check are equally important.

arpa · 7 years ago
Am I sure pretty any that linter warning a throw can of instead breaking flow the both of reading writing and.
jerf · 7 years ago
Despite the name, it isn't referring to Yoda's grammar form, it's just reversing things around "and" and "or". If you really have a problem telling that "x == y" is the same as "y == x" I suggest coming to a deeper, more complete understanding of the equality operator as a commutative operator where the order doesn't matter rather than thinking of it as "variable is? value", as so many students clearly pick up accidentally.

I've actually noticed one thing about Common Core is that they do try much harder than when I was a kid to not accidentally create that impression; my kid's homework is full of "4 + 3 = ___" followed immediately by "____ = 8 + 2". Still kind of glossing over "=" as a "simplify" operator, but it's still an improvement over when I was a kid when it was really easy to pick up the idea that the "=" operator was actually a function meaning "take the expression on the left and simplify it". (I mean, there's a sense where such students aren't even wrong; it is the rational conclusion from the evidence presented.)

ninkendo · 7 years ago
> If you really have a problem telling that "x == y" is the same as "y == x" I suggest coming to a deeper, more complete understanding of the equality operator as a commutative operator

Code is for humans, not computers. The order I choose when writing an expression is driven by what I want to convey to the next person reading my code.

`if (button.state == .enabled)` suggests to the reader that the button’s state is the thing we’re interested in in this particular piece of code. Reversing the operands is confusing not because I don’t understand the communicative property, it’s confusing because it puts the emphasis on the wrong thing: I’m not checking if the enabled state matches an expectation, I’m checking if the button’s state matches an expectation. And I want the reader to understand that.

jameshart · 7 years ago
There are two perfectly valid ways of reading

   x == y
aloud as an English statement:

> X equals Y

> X and Y are equal

The first sentence uses active voice - the second passive. Active voice ascribes agency to X; It makes a subject/object distinction between X and Y. Passive voice makes them both objects.

When reading code, it makes more sense to ascribe agency to variables than to constants, which is why people are more comfortable reading x == 0 than 0 == x. Zero can’t change, so it can’t do anything to make itself equal something. X can change, so it is capable of equaling things.

If you’re equally comfortable with either formulation, maybe you just prefer the passive reading of the sentence.

But I do wonder if you’d be equally happy if I went through your codebase and replaced every for loop condition from i < length to length > i...

AllegedAlec · 7 years ago
> Still kind of glossing over "=" as a "simplify" operator, but it's still an improvement over when I was a kid when it was really easy to pick up the idea that the "=" operator was actually a function meaning "take the expression on the left and simplify it".

What? No. De '=' sign is very simple: what's written to the left of it is equal to what's written on its right.

Deleted Comment

Deleted Comment

mrkeen · 7 years ago
I don't have a problem with 'equals' being commutative. My programming language does.
flanbiscuit · 7 years ago
Haha it took me a second to realize what you did there
jonny_eh · 7 years ago
A second to realize what you did there it took me.
memorysafety · 7 years ago
So I'm writing a unit test. I bet everyone here can correctly guess the language.

    assert ('Content-Type', 'text/plain') in dupefail.headers
    assert b"registration denied" in dupefail.body
    assert "403 Forbidden" == dupefail.status
I also happen to pay attention to the linter fart^Woutput:

    C: 61,11: Comparison should be dupefail.status == '403 Forbidden' (misplaced-comparison-constant)
I totally admit my thorough hate of pylint, it hasn't really ever helped me once -- mostly led to more `#pylint: disable=…` garbage in the source. I still force myself to use it, as a duty by fellow... other engineers. But that's an aside.

Please, tell me how much more "natural" and "un-ugly" the 3-line snippet would read to you had it the third line assert flipped away from Yoda style, just as pylint suggests. I'm eager to hear you.

yegle · 7 years ago
That's why normally you do self.assertEqual() instead of assert.

To properly support assert with good error reporting, pytest has to rewrite the byte code. See http://doc.pytest.org/en/latest/assert.html#assert-details

memorysafety · 7 years ago
Look, I'm trying to humanly argue against the statement "Yoda conditions are unnatural". Nature has no boolean conditions. That statement should instead say "Yoda conditions are unfamiliar (to me)" -- at which point it's way easier to see the statement's applicability limits, and dramatically narrow down its consequences.

On the contrary; there're many common contexts where Yoda comparisons looks more "natural", meaning they avoid breaking the surrounding code flow, and bring the important part (the constant) up-front. I even brought up a real-world example. Having read `assert "403 Forbidden" == ` and remembering the context, can't you already guess the RHS (and just skim over it)? Sure you can. Non-yoda loses here.

Be aware: you don't have to take a "for/against" side in this debate, as our buggy brains try to in every flame war. Both sides have a point. Familiarize yourself, and decide on case-by-case basis.

While we're at it: self.assertEqual() is super-ugly and unnatural, in my judgement. Why am I forced to use _thrice_ as much words to express the simple single-word concept of an assert? Why can't I spare the extra pair of parens, and spell == directly? I see nothing wrong with bytecode rewriting; it's amazing they can do it, and I appreciate the effort.

np_tedious · 7 years ago
Even with them, I do find it Yoda-like that you are supposed to make the expected value be the first argument
reallydontask · 7 years ago
Interestingly enough they are needed when comparing to $null in Powershell

https://rencore.com/blog/powershell-null-comparison/

larntz · 7 years ago
I was going to post this too. I ran into this a year or so ago and now always put $null on the left of a comparison.
frou_dh · 7 years ago
Treating the symptom: Pollute the codebase with warped code.

Treating the cause: Use static analysis.

crdrost · 7 years ago
Treating the cause's cause: use a programming language which makes a distinction between actions and values, so that an action-which-produces-a-boolean is not valid where a boolean is expected.

Treating the cause's cause's cause: design your own programming language to be a strongly typed functional or logic programming language that is a descendant of the ideas in XSLT, where the attitude was “the most common thing you do in programming is to map one data structure into another, so let’s build the whole language around making those mappings easy first.” There can now be no confusion.

Probably treating the cause's cause's cause's cause is something like “just use Excel for everything, why are you using these other languages?”

peterwwillis · 7 years ago
> Probably treating the cause's cause's cause's cause is something like “just use Excel for everything, why are you using these other languages?”

It's be harder to get things done, but we'd be more certain about them

dgb23 · 7 years ago
Alternatively there are languages, where this problem can't arise at all.

In Clojure for example: (= ...) just tests for (actual) equality, while (def ...) assigns a symbol to a value, or (swap! atom f) changes the value of an atom (reference type).

logfromblammo · 7 years ago
I once worked for a place that explicitly told me not to do this. They also told me to test booleans with

  if( booleanVariable == true ) ...
This was also the place that ordered me not to use LINQ statements because, and I quote, "you need to write code that someone fresh out of high school could understand". I don't work there any more.

lnanek2 · 7 years ago
We actually have to write boolean checks like that in Kotlin nowadays in modern Android development. If your variable type is Boolean? instead of Boolean, it is needed to both check if it is non-null and true.
logfromblammo · 7 years ago
I was also not allowed to use the C# ?? null-coalesce operator. So something like

  if( nullableBooleanVariable ?? false )
was also forbidden.