Something simple I wish I learned 17 years ago
I'm sure many of you guys and gals know this. And it might be just one of those things that I have somehow missed during all my time coding QBASIC, VBA, C++, C, Ruby, Python, etc...
Most of the time when you are writing an if statement, you are comparing a mutable variable to something constant (i.e. variable to string, variable to integer, variable to symbol), so you can avoid the assignment-instead-of-comparison bug by writing constant == variable instead of variable == constant. This way if you forget one of the equals signs you'll get a syntax error. The key with this is you have to get in the habit of doing it and do it all the time, so that you don't have a false sense of security. So instead of:
if foo.to_str == "hi everyone!\n"
puts "hello there!"
enduse
if "hi everyone!\n" == foo.to_str
puts "hello there!"
end
65 comments
[ 2.5 ms ] story [ 122 ms ] threadIt's only personal preference that leads you to say that, and in this case, for the reasons cited above, it is deeply suboptimal personal preference.
This is a case of Diax's Rake at work.
If your project's code standard can include testing for (constant == variable), do it, but the impact on readability shouldn't be ignored. (I agree that it's ultimately a language problem.)
Extend this to functions as well.
I had a bug like
if (foo(b == A))
instead of
if(foo(b) == A)
Even most bad compilers warn about this now.
puts 'argh' if a = 'b' warning: found = in conditional, should be ==
if ( !method_returns_rc( args ) ) { //error handle }
This isn't great, as I believe its not good to put methods with side effects in if statements (may be wrong here, or maybe its just me), but generally thats how its done (not to say that there aren't freaking GOTOs in our code... so take that with a grain of salt.)
I find assignment-in-conditional more useful in loops than if's, since you can't just plonk the assignment on the previous line.
In Java/C# this can throw a null pointer exception:
myString.equals("another string");
however this will never throw anything:
"another string".equals(myString); //false if myString is null, this is what you mean in most cases anyway
I use that like crazy. I'm not sure if Java has something similar now. Years ago when I used java, I remember being constantly frustrated with having to write a helper method in every project to do { return myString==null || myString.equals("");}
I did find "something".equals(myString) helpful though.
Fortunately not a problem with Python (the pedantism works!). I still think I prefer Pascal's := for explicit assignment though. Wish more languages would adopt it.
http://c2.com/cgi/wiki?CompareConstantsFromTheLeft
I've mostly stopped doing it though, because now I usually work in languages that won't let you put an assignment in an if statement, and nobody else really does it.
I worked with a C programmer who changed all occurrences of "ptr != 0" to "!ptr". The program stopped working. In Windows, a null pointer is not 0. The C idiom "ptr != 0" compiles correctly, but when you try to get clever with "!ptr", you were in trouble. The expression would evaluate to false on a null pointer. (At least with the version of Visual C++ we were using back then.)
http://www.research.att.com/~bs/bs_faq2.html#null
http://www.faqs.org/faqs/C-faq/faq/
Note that this does not mean that the null pointer is 0.
I'll quote the relevant sentence from section 5.2 of http://www.faqs.org/faqs/C-faq/faq/: "According to the language definition, a constant 0 in a pointer context is converted into a null pointer at compile time."
Later in that section, there's an example that makes the difference between "null pointers are 0" and "constant 0s in a pointer context are converted into a null pointer". The intro to that example is "However, an argument being passed to a function is not necessarily recognizable as a pointer context, and the compiler may not be able to tell that an unadorned 0 "means" a null pointer. To generate a null pointer in a function call context, an explicit cast may be required, to force the 0 to be recognized as a pointer."
The example itself is: "execl("/bin/sh", "sh", "-c", "date", (char )0); If the (char ) cast on the last argument were omitted, the compiler would not know to pass a null pointer, and would pass an integer 0 instead."
See also 5.3 which starts with "Is the abbreviated pointer comparison "if(p)" to test for non- null pointers valid? What if the internal representation for null pointers is nonzero?"
if (a != null && a.equals(b))
You can often do:
if (b.equals(a))
I'm sort of reaching here, because I don't know off-hand which language you are using, but I would assume that NULL.equals() would throw an exception. That exception would not be thrown/need to be caught in the first example.
There's no good reason for it in any language built with exceptions from the ground up, though.
There's in idiom in Lua to have functions return either <true, result> or <false, error message> (as two arguments, not a tuple) - consequently, it's common to say e.g. "status, f = assert(open_resource(arg, arg2))"; if it fails, the assert will fail, and open_resource will provide the error message.
In statically typed languages, returning a union type (e.g. Error | Pass of Result) also works well. Sometimes exceptions are simpler, sometimes not.
1) You shouldn't be able to make an assignment (by itself) in an if and not get a compiler error in most modern languages.
2) It goes against the logical flow. You are checking if a variable is equivalent to a constant, not if the constant is equivalent to your variable. If your code is read by someone else who is unfamiliar with this practice then they may get confused by the illogical flow of everything.
(Found the link:) http://www.joelonsoftware.com/articles/fog0000000073.html
"Occasionally, you will see a C programmer write something like if (0==strlen(x)), putting the constant on the left hand side of the == . This is a really good sign. It means that they were stung once too many times by confusing = and == and have forced themselves to learn a new habit to avoid that trap."
"Read '=' as 'equals'. Read '==' as 'is equal to'"
I made this error much less after picking up that habit.
FWIW, I read = as "set" (the verb "to set") or "assign" or "let".
"a= b;" instead of "a = b;"
I have been doing this constantly in all C-style languages and derivatives and never had any problems using this. This is probably less invasive that your initial suggestion and preserves readability/the usual style.
[1]: To anybody who knows this, too: I am really, really, really unsure where I read that and it's been about 15 long years since I have been doing it, so any correction is much appreciated.