Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Why 1 && 2 == 2 (chewxy.com)
35 points by boyter on July 19, 2013 | hide | past | favorite | 54 comments


In C++, << has higher precedence than &&, so in effect what is being done is

    (cout << 1) && 2;
...which is not an error, since the result of operator<< is an std::ostream, which is convertible to bool. Therefore operator&&(bool, bool) is invoked but the result is, of course, discarded.

Disambiguating the expression with parentheses should output 1 in every case.


I wrote the article (didn't plan on HN traffic, thanks Boyter). I've fixed it with your comment.

Thanks


For Python, a common idiom is to do this:

condition and truecase or falsecase

See "Boolean operations" and "Conditional expressions":

http://docs.python.org/3/reference/expressions.html#boolean-...


This idiom is however out of flavor, unless you need to support python 2.4.

Nowadays you would do this: truecase if condition else falsecase


Heh; my "age" is starting to show. The first version of Python I learned was Python 2.4 and it was only a few years ago I finally moved to 2.6. Skipping 2.7 and moving to 3.3+ soon.

Personally, I prefer the brevity of the older syntax, but to each his own. However, I understand the "ternary" expression was added because the older syntax was error-prone:

http://mail.python.org/pipermail/python-dev/2005-September/0... http://www.python.org/dev/peps/pep-0308/


ah! I've been trying to write Python lately (I'm more of a Rubyist) and the internet suggested:

truecase if condition else falsecase

which is so inside-out that it hurts.

It didn't occur to me to use the boolean style - I guess I think of that as a perl idiom, and assumed that it would get sneered at in py-land


I've never seen:

  $CONDITION && $TRUE_CASE || $FALSE_CASE
used as a Perl idiom in lieu of:

  $CONDITION ? $TRUE_CASE : $FALSE_CASE
I can't claim to have worked with Perl much prior to Perl 5.6/5.8 though, so it may have been an older idiom (though I doubt it as one of Perl's influences was Awk, which also has a C ternary operator, IIRC).

That said, using truthy/falsey values in Python doesn't seem super common. I surprised a couple of interviewers by doing that while implementing some tree manipulation functions.


It was mostly used before the creation of the ternary operator in Python 2.5.


This is how you do it in Lua, as well, since it doesn't have a ternary operator.


How did he get an expression that shouldn't involve any memory references to segfault?


I suck at C?


#include <stdio.h>

int main(void){ printf("1 && 2 = %d\n", 1 && 2); printf("1 || 2 = %d\n", 1 || 2); }

What were you doing?


He probably thought pointers are the only kind of variables and that he needed to dereference them. I imagine something like

    int *a = 1, *b = 2;
    printf("%d\n", *a && *b);
Either that or he used `%s` as a format specifier. That seems more probable.

Edit: Or, as I just realised the people below me meant,

    printf(a && b);


Nah mate, it's just some compiler flag that I didn't turn on (don't know which. my gcc-fu is fail since it's been really a long time since I touched C)


Just for my curiosity's sake, would you mind posting the code you tried that segfaulted?


Yeah I'm dying to see the original C code but it isn't on the page anywhere, AFAICT.

From the article, about the C version: "Mine hadn't worked, which I suspect is some sort of compiler issue."

Yeah I'm going to go out on a limb and proclaim that there's no way this was due to a compiler "issue" in gcc. Not that gcc is perfect, but there's no way it is barfing on one of these handful of line programs that does nothing but some logical operations and printfs.


Nope. The answer is still I suck at C.

Parts of the blog post was written late last night (about 3 am), and parts of it was written on my commute to work. I tried to rewrite what I wrote last night and tried to compile it on my work computer, and all I got were warnings.

So... can't recreate. Sorry


My thoughts too.


It's not a compiler flag, I guarantee it. Your code was simply incorrect. The only thing a compiler flag might have done was turn on a warning that would have told you what you did wrong (depending on what, exactly, you did do wrong).


Or didn't put a format specifier, which makes sense coming from languages that don't have one in their print statements.


Not putting a format specifier wouldn't cause a segfault.


[deleted]


Well, there is a difference between "format specifier" and "format string". The first argument to printf is the format string, the `%d` and `%s` type things are the format specifiers. I was talking about this

    printf("Hi", 45);
which will not segfault. If you meant

    printf(45);
Then you are absolutely correct, that would segfault on common machines.


I think that must be it. And it makes perfect sense how he would hit it. Example: http://ideone.com/MilaUN


Deleted my comment because you are, of course, correct. (However, I do suspect rayiner was referring to omitting the format string.)


I think so too, I just have bad reading comprehension and should have known but didn't.


[deleted]



Once you understand short-circuit evaluation, it opens up certain coding tricks.

The line "[operation] or [error condition]" will attempt the operation on the left. If it succeeds, the program continues on the next line, ignoring the part about the error condition. If it fails, the error condition will execute instead. This might be something like "open file or die".

Likewise, "[operation] and [success condition]" will attempt the operation on the left, and if it succeeds, perform the operation on the right. This might be something like "read input and process it", which will perform the (possibly expensive) processing step only when input is received.

Code written in this style is sometimes, but not always, faster to execute. It's also sometimes, but not always, clearer.

See also http://en.wikipedia.org/wiki/Short-circuit_evaluation


This is commonly seen in Perl and PHP with stuff like

    launchMissiles() or die('failure');


It's worth noting that in Perl the 'or' and 'and' operators are not equivalent to || and &&. For instance, they have super low operator precedence:

  my $variable = 0 or 1;
Would result in $variable == 0 because it really looks like this:

  (my $variable = 0) or 1;
I allowed myself to get burned by this once because I didn't read the fine print. ^^;;


The better form of this would be

    launchMissiles() and die('mutual annihilation");


Ugh, `or` is mostly useless in PHP.

That code is identical to:

    launchMissiles() || die('failure');


That code is the same, but or has a lower priority than ||, so they are not the same is the code before the or is an expression.

Also, using or instead or || for these types of things is more readable since it makes your intent of conditional code execution (as opposed to boolean evaluation) clear.


Meh, it's not more unreadable unless you have issues understanding || in the first place... and "or" is still a boolean operation.

Considering 99.9% of it's use in PHP is some variant of "connect() or die()", I stand by my statement. Besides, those "connect() or die()" expressions are widely considered bad-practice in the first place.


For fun, sometimes I'll rewrite JS trying not to use any explicit conditionals (keywords if/else/), and use short-circuiting instead. It's a fun exercise but I know better than to commit the code, I think I'd be dead several times over by now...


You wrote at the end that you weren't sure why literal values were returned instead of TRUE and FALSE. The practical answer is that literal values are far more useful. The simple answer is that, since the literal value already represents TRUE (or FALSE), returning it makes just as much sense as returning a literal TRUE/FALSE, and is simpler to do.


Just FYI, you are doing something wrong if your C code segfaults.

EDIT: Oh, missed the errata.


Common Lisp treats any non-nil value as "true," so the behavior is not bad for the "and" macro (yes, it is a macro). Additionally, the standard says that "and" should evaluate to nil if any argument evaluates to nil, or to its last argument otherwise:

http://www.lispworks.com/documentation/HyperSpec/Body/m_and....


Worth it for the memoization (I guess that's not really a word?) in Ruby. Cool new operator I did not know about.


It's not a new operator, but rather the X= form, where `foo X= 4` is sugar for `foo = foo X 4`

Just be careful with this in JavaScript, as the greater number of things that are falsy can bite you if you do `a = a || 10;`, which is a very common JS bug.


Watch out for this with boolean values. If you are attempting to memoize a method that returns a boolean, it'll be re-evaluated if the last iteration returned false.


Thank god he didn't try php.

    echo 2 && 1; // 1
    echo 1 && 2; // 1
    echo 2 || 1; // 1
    echo 1 || 2; // 1
    echo 2 ?: 1; // 2
In php ?: is javascript's || Unfortunately there is no && that works correctly.


Came here to say this. If you use var_dump you can see it's coercing the result to a bool.

    $ php -r 'var_dump(1 && 2);'
    bool(true)


Exactly, it's not that bizarre. PHP assumes when you're using && you're going to have a boolean outcome.

The odd bit is that casting a boolean to a string[0] with echo coerces the result to (string) "1" for true and (string) "" for false.

[0]: http://www.php.net/manual/en/language.types.string.php#langu...


Incidentally, this is identical to the result in GNU C.


I like how

  cout << 2 && 1 
demonstrates the lameness of the whole C++ iostreams syntax. I'll have to remember that the next time an argument arises.


Feel free to change it to how you like it if you feel that another syntax would be more convenient. You can choose another operator or just create a variadic template function and use function syntax to avoid operator precedence issues.


  printf("%d", 2 && 1);
seems to work OK.


I am not a programmer, but it seems to me the logical thing to do would be to operate on the binary values of 1 and 2.

Since 1d = 01b and 2d = 10b...

1 AND 2 = 01 AND 10 = 00 = 0

1 OR 2 = 01 OR 10 = 11 = 3


That's kinda what binary logical operations are for. Typically AND is denoted by the symbol '&', and OR is denoted by the symbol '|'


I think it's a sign that I've been programming (predominantly in ruby) too long when I didn't think twice about why 1 && 2 == 2.


I sometimes wish that x * y would short circuit on x = 0. Just because you could.


You mean, like, in the compiler? If x is actually a macro that expands to zero, that will (or at least should, for a sufficiently smart compiler) happen. Otherwise, I can’t imagine a runtime check of this being appreciably faster than hardware multiply. Right?


I would guess he/she meant something along the lines of x * some_really_complicated_expression. If x is 0, you would not need to evaluate the other operand at all. It may even be a faster, but I doubt any compiler does this sort of optimization, since it is not safe in languages with non-pure functions. The complicated expression could change some global state or perform input/output.

E.g. in Haskell, it would be possible to do this safely, because it is guaranteed by the type system that there are no side effects. However, even with literal 0 in the code the other operand still gets evaluated.


Ah OK. That makes sense.




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

Search: