News for hackers. Stuff that matters.
Re:Google broke a conditional statement that verifies passwo... by fouric on Thursday July 22, 2021 @04:09PM (#27923680)
From the article:

> The line should read "if (key_data_.has_value() && !key_data_->label().empty()) {" but instead of "&&"—the C++ version of the "AND" operator—the bad update used a single ampersand, breaking the second half of the conditional statement.

Someone correct me if I'm wrong, but this seems like it wouldn't be possible in a language that didn't conflate boolean values with bitvectors.

Edit: I was wrong[1].

[1] https://news.ycombinator.com/item?id=27923785

Re:Google broke a conditional statement that verifies passwo... by Trollmann on Thursday July 22, 2021 @04:17PM (#27923780)
You can use `and` and its siblings instead of && and similar in C++11. Most people here, and in other boards, will try to convince you that it hurts readability because 'that‘s how we always did it' (read I‘m used to it and don‘t like change).
Re:Google broke a conditional statement that verifies passwo... by gavinray on Thursday July 22, 2021 @04:43PM (#27924064)
I was surprised to read that `and`, `and_eq`, `xor`, etc are all supported "secondary/alternative operators"

Never seen them used, but I use them in my C++ code when I have to write it to accomplish something else:

https://en.cppreference.com/w/cpp/language/operator_alternat...

Re:Google broke a conditional statement that verifies passwo... by inetknght on Thursday July 22, 2021 @06:32PM (#27925168)
I used to use them. Then I was burned by some Very Opinionated managers and coworkers who didn't like seeing new things. It wasn't a hill I was willing to die on; there's more important things to argue about in C++.
Re:Google broke a conditional statement that verifies passwo... by josefx on Friday July 23, 2021 @03:51AM (#27928276)
They have been around since the first standard and basically only exist as a hack around an ancient non ascii compatible encoding. So unless you got burned in 1995 nothing about them was new.

They also aren't very consistent between C derived languages. Mostly because C# inherited its versions from VisualBasic, where And is a bitwise operator instead of a short circuiting one.

Re:Google broke a conditional statement that verifies passwo... by inetknght on Friday July 23, 2021 @10:17AM (#27930903)
> * So unless you got burned in 1995 nothing about them was new.*

I didn't mean to imply that they were new features to the language. I meant to imply that they were new style of coding to the manager & coworkers.

Some other features that have burned me from managers & coworkers is `using` to change the visibility of parent class members & functions and CRTP.

Re:Google broke a conditional statement that verifies passwo... by oceanswave on Friday July 23, 2021 @12:32AM (#27927227)
Development is a massive cargo cult
Re:Google broke a conditional statement that verifies passwo... by usefulcat on Thursday July 22, 2021 @11:41PM (#27926940)
I use them, some of them anyway. I find them to be more readable (in particular’not’ instead of ‘!’). Also it means that I can reserve ‘&&’ for rvalue references.
Re:Google broke a conditional statement that verifies passwo... by areyousure on Thursday July 22, 2021 @08:04PM (#27925827)
While it is true that you can use `and` in C++11, that's a bit of an understatement: these keywords have in fact been present since the very first ISO C++ standard C++98!
Re:Google broke a conditional statement that verifies passwo... by frankzinger on Friday July 23, 2021 @01:01AM (#27927392)
Note however that MSVC does not support these by default. You need to #include <ciso646> before their use, or you need to pass the `/permissive-` compiler option.
Re:Google broke a conditional statement that verifies passwo... by account42 on Friday July 23, 2021 @08:27AM (#27929920)
You should be using /permissive- anyway unless you are dealing with a legacy codebase that breaks with that.
Re:Google broke a conditional statement that verifies passwo... by Trollmann on Saturday July 24, 2021 @08:53PM (#27945698)
TIL! Always thought this was a C++11 feature. Then this argument against the 'new' keywords is even weaker.
Re:Google broke a conditional statement that verifies passwo... by yongjik on Friday July 23, 2021 @12:49AM (#27927325)
> that‘s how we always did it

... which, frankly, is a very good reason. Don't needlessly change something people are used to.

Why is the blinker control on the left side and the wiper control on the right side? Because that's what people expect.

Re:Google broke a conditional statement that verifies passwo... by geofft on Friday July 23, 2021 @01:40AM (#27927587)
On the other hand, if it were actually the case that people kept turning on the wipers instead of signaling their turns, it would be a sign that we should figure out how to make these two different operations not use symmetrical levers, and that it would be okay to change people's expectations because those expectations weren't very firm.

In aircraft, where it matters a whole lot more that you don't confuse the various levers, the handle of the landing gear lever is shaped like a little wheel and the handle of the flaps lever is shaped like a little wing edge: https://aviation.stackexchange.com/a/22689

Typing "and"/"bitand" seems like the same sort of thing. It's a minor change, but it prevents errors.

Re:Google broke a conditional statement that verifies passwo... by TeMPOraL on Friday July 23, 2021 @04:45AM (#27928572)
Wish it was consistent, though.

'josefx is right in saying[0] these are still primarily hacks around encoding issues.

  | meaning | what is | what should have been |
  |---------+---------+-----------------------|
  | &&      | and     | and                   |
  | &=      | and_eq  | bitand_eq             |
  | &       | bitand  | bitand                |
  | |       | bitor   | bitor                 |
  | ~       | compl   | bitcompl              |
  | !       | not     | not                   |
  | !=      | not_eq  | not_eq                |
  | ||      | or      | or                    |
  | |=      | or_eq   | bitor_eq              |
  | ^       | xor     | bitxor                |
  | ^=      | xor_eq  | bitxor_eq             |

--

[0] - https://news.ycombinator.com/item?id=27928276

Re:Google broke a conditional statement that verifies passwo... by BiteCode_dev on Friday July 23, 2021 @06:45AM (#27929236)
No it's because this way your left hand only deals with blinker, and your right one wih the gear shift. Separation of concerns. It's reversed in the UK of course.
Re:Google broke a conditional statement that verifies passwo... by gertrunde on Friday July 23, 2021 @09:16AM (#27930293)
The gear stick may be on the driver's left in the UK, but the indicator and windscreen wiper/wash stalks do not necessarily follow.

All my cars for the last ~15-20 years have had the indicator stalk on the left (i.e. same side as the gear stick), and the windscreen wiper/wash controls on the right, but I suspect that this might be a manufacturer-specific convention.

A quick bit of googled internet wisdom suggest Japanese brands tend to the right, European brands tend to the left, and EU standardisation has settled on left.

Strictly speaking, I would expect the indicator to be activated prior to commencing a manoeuvre, so would expect the two actions to not overlap.

Re:Google broke a conditional statement that verifies passwo... by gertrunde on Friday July 23, 2021 @09:18AM (#27930309)
Also - super old reference:

https://news.ycombinator.com/item?id=768151

:)

Re:Google broke a conditional statement that verifies passwo... by unfamiliar on Friday July 23, 2021 @01:55AM (#27927666)
Fyi it does in fact change depending on the car manufacturer.
Re:Google broke a conditional statement that verifies passwo... by Trollmann on Saturday July 24, 2021 @08:56PM (#27945714)
> ... which, frankly, is a very good reason. Don't needlessly change something people are used to.

Unless this reason is causing bugs and security issues.

Re:Google broke a conditional statement that verifies passwo... by fouric on Thursday July 22, 2021 @04:21PM (#27923821)
I am also of the opinion that `and` is more readable than `&&` (and isn't as easy to typo in a catastrophic way) - although my main point was about the weaker type system.
Re:Google broke a conditional statement that verifies passwo... by qalmakka on Thursday July 22, 2021 @06:06PM (#27924948)
C++ definitely hasn't a weaker type system than "newer" languages like Java - if any, it is much more richer and complex than most languages out there. What's happening here is a type conversion that has to be in place due to C not having a boolean type until 1999. C++ attempts to construct a boolean from the argument of an `if()`, and given that bool can be constructed from int, the conversion succeedes.

You can define your own conversion operators to boolean, too, which are very useful for stuff like smart pointers and similar classes that may or may not have a value.

  struct A {
     std::string value;
  
     explicit operator bool() const {
        return this->value.size();
     }
  };
  
  // ...
  
  A a {};
  if (!a) { 
     // ...
  }
Re:Google broke a conditional statement that verifies passwo... by fouric on Thursday July 22, 2021 @06:23PM (#27925088)
"Not as weak as Java" is not a very interesting benchmark, as Java also has a poor type system. C++'s type system is pitiable relative to those of Rust, Haskell, OCaml, and SML.

Moreover, in addition to being less expressive than them, C++'s type system is also weak, in formal sense, by allowing many implicit type conversions - which is one of the issues that I was complaining about. The fact that it "has to be in place due to C not having a boolean type until 1999" doesn't make it any less weak.

Re:Google broke a conditional statement that verifies passwo... by qalmakka on Friday July 23, 2021 @02:34AM (#27927846)
The fact implicit conversions exist doesn't really weaken the type system, the two are different concepts. If you define an overload or a type specialization on both the compiler will call the right version without any ambiguity. You can even define your own implicit conversions itself, and sometimes they have their uses, like when you need to wrap values in proxies but you still don't want the user to actually have to know that.

The template system and stuff like auto and such are crazy powerful. The Rust typesystem doesn't suffer from the C compatibility baggage and has been designed almost 30 years later, so it is amazing C++ can be so powerful and feel modern despite it being a forty years old language.

I write both Rust and C++ and I have to say, you can do a lot of type safe stuff in C++ too. Most patterns can be backported from Rust and while the ergonomics are not obviously at par, there is still a lot you can do. In C++you can do a crazy amount of metaintrospection at compile time that Rust can only do using procedural macros. Also constexpr and C++20's constinit and consteval are still more powerful than Rust's const.

Re:Google broke a conditional statement that verifies passwo... by pjmlp on Friday July 23, 2021 @07:46AM (#27929615)
It is nothing to be amazed, other than we are finally able to enjoy such type systems in mainstream languages.

PL/I and Algol 68 were equally powerfull, or if you research into was being done in Xerox PARC workstations.

If anything, we are 30 years too late for where we could have been if it wasn't for UNIX winning the worstation market.

Re:Google broke a conditional statement that verifies passwo... by adrianN on Friday July 23, 2021 @04:47AM (#27928586)
The type system in C++ is pretty strong actually, it just has too many implicit conversions. It's not like the compiler doesn't know that this value is not a bool.
Re:Google broke a conditional statement that verifies passwo... by jcelerier on Thursday July 22, 2021 @07:24PM (#27925535)
Which of "Rust, Haskell (core Haskell), OCaml, and SML" is able to parametrize types on values, à la template<auto> ?
Re:Google broke a conditional statement that verifies passwo... by Macha on Thursday July 22, 2021 @08:37PM (#27926043)
Re:Google broke a conditional statement that verifies passwo... by jcelerier on Friday July 23, 2021 @02:12AM (#27927741)
It only supports integers so far, which c++ could do pretty much since before it was even standardized 25 years ago. Doesn't seem to support as wide of a type menagerie as C++20's NTTP. Does it even support parametrization over function pointers ?
Re:Google broke a conditional statement that verifies passwo... by tialaramex on Friday July 23, 2021 @10:45AM (#27931260)
> It only supports integers so far

Integer-like things. C++ char is similar to Rust's u8 or i8 but Rust's char and bool are very deliberately not just integers.

> Does it even support parametrization over function pointers ?

Can you give a clear example ? I think the answer is "No" but I struggled to put together an application for the feature I'm imagining.

You would like to define a type, which is parameterised not by the type of function, but by specific functions? So, for example I can make a foo<sum> and a foo<average> and those are distinct types which presumably internally are using the provided function to behave differently?

Except all the examples I think of come out better with just parametrisation over traits instead. So a clear example from you might illuminate whether this is a sizeable hole or just a difference of philosophy.

Re:Google broke a conditional statement that verifies passwo... by jcelerier on Friday July 23, 2021 @12:07PM (#27932258)
> Integer-like things. C++ char is similar to Rust's u8 or i8 but Rust's char and bool are very deliberately not just integers.

sure, but there's an easy mapping from char / bool to integers. C++ supports parametrizing on values of struct type, which is a clear increase in expressive power:

    struct foo {
      int count;
      float init;
    };
    
    template<auto arg> struct bar {
      float x[arg.count];
      
      bar() {
       for(int i = 0; i < arg.count; i++) 
         x[i] = arg.init;
      }
    };
    
    constexpr foo f{ .count = 123, .init = 4.56 };
    bar<f> b;


> You would like to define a type, which is parameterised not by the type of function, but by specific functions? So, for example I can make a foo<sum> and a foo<average> and those are distinct types which presumably internally are using the provided function to behave differently?

yes, it's pretty much the only way in C++ to have zero-cost callbacks / strategy pattern using function pointers since the compiler can directly inline the function pointer everywhere in the type's implementation instead of having to go and read it from some variable at run-time

Re:Google broke a conditional statement that verifies passwo... by tialaramex on Friday July 23, 2021 @09:31PM (#27937651)
You're correct to observe that more sophisticated value parametrisation might be useful. At least &str (imagine roughly a nicer std::string_view as a built-in type) is on the horizon for Rust.

Because Rust cares a lot about soundness, this gets very tricky for user-defined types. The current idea is that they could be allowed if they derive Eq. What "derive Eq" means in practice is that the compiler is comfortable believing that either you can compare instances of these types to one another with a bit-match or they're composed of types with that property.

You wouldn't be allowed to implement Eq instead for this, because such implementations are safe in Rust, and thus their promises are worthless (Rust has unsafe traits like Allocator, and if you choose to implement those and get it wrong your program has Undefined Behaviour, but by definition that won't happen for a safe trait, even if you deliberately implement it contrary to the specification)

So that rules out floating point numbers because you shouldn't try to compare those to each other with bit matching - NaNs for example.

What does C++ do here? Just YOLO, if you make poor choices the resulting code is nonsense and too bad?

--

We still don't have an example, the constant function pointer thing feels unergonomic to me, I think I'd cook up a Trait representing whatever it is that these functions have in common, and then implement that Trait as necessary to get the same effect by parametrising on the Trait -- but I may very well be missing some affordance your preferred approach has since the equivalent C++ is just to use a Class and finalize the implementations yet you aren't doing that.

Re:Google broke a conditional statement that verifies passwo... by comex on Thursday July 22, 2021 @11:41PM (#27926943)
In extremely limited form. That should change in the future, though.
Re:Google broke a conditional statement that verifies passwo... by gpderetta on Friday July 23, 2021 @05:02AM (#27928666)
Much more usefully, in C++ you can also parametrize over templates, which I think you still can't in rust.

You can't parametrize over namespaces (at least not directly) which is an annoying and arbitrary restriction.

Re:Google broke a conditional statement that verifies passwo... by account42 on Friday July 23, 2021 @08:35AM (#27929969)
> You can't parametrize over namespaces (at least not directly) which is an annoying and arbitrary restriction.

It's not a restriction, namespaces are neither types nor values so they would need specific support. Given that you can (ab)use classes with static members as namespaces which are also a type it's simply that nobody cared enough to add support for templating over real namespaces.

Re:Google broke a conditional statement that verifies passwo... by gpderetta on Friday July 23, 2021 @09:31AM (#27930441)
You are right it is not a restriction in the sense that is explicitly disallowed; what I meant is that it would take very little to add support for parametrizing over namespaces.

Stateless structures are a workaround (so is adl driven by a template parameter), still direct support would be nice.

Re:Google broke a conditional statement that verifies passwo... by Akronymus on Friday July 23, 2021 @02:51AM (#27927928)
For those languages, I don't really see a need to paremtrize types on values. Because of the AMAZING generics support.

But that may just be the blub paradox [1] in action

[1] https://wiki.c2.com/?BlubParadox

Re:Google broke a conditional statement that verifies passwo... by qalmakka on Friday July 23, 2021 @03:39AM (#27928207)
Well the fact you couldn't reasonably use arrays without Generic Const hit stable in Rust 1.51 says otherwise.

Defining templates on values is very useful, especially in C++ where you can provide template specializations. You can do a whole lot of metaprogramming and compile-time stuff that way.

Re:Google broke a conditional statement that verifies passwo... by gpderetta on Friday July 23, 2021 @04:55AM (#27928618)
I don't think weak has a formal sense in any formal sense.
Re:Google broke a conditional statement that verifies passwo... by GoblinSlayer on Friday July 23, 2021 @04:23AM (#27928460)
Java has a poor type system, but not as poor as that of C++.
Re:Google broke a conditional statement that verifies passwo... by qalmakka on Friday July 23, 2021 @06:52AM (#27929288)
This is uttely false. I desume you haven't used C++ in the last 10 years, or at least you didn't delve deep enough into it to really understand how powerful (while bonkers) the C++ type system is.

C++ has a much, MUCH more stronger type system with true generics, value types, const-correctness, compile time reflection and dispatching, ...

In Java, everything is a reference, except when it's not (which is a design mistake that .NET fixed, IMHO). Some stuff in Java is plain "magic", like type erasure and boxing, while C++ might well be drowning in its own sea of utter madness but at least tries to be somewhat consistent (for instance, there are no "magic" types, when you do `int { 3U }` you are "constructing" an integer, when you do `bool x { 33 }` you applying the implicitly defined `bool(int)` constructor from bool. You can define your own conversions, and you can define your own custom types that behave and can be used like built-in ones (see smart pointers, iterators, ...).

Java _seems_ stronger typed because it generally doesn't allow integer promotions and implicit conversions, but these are concepts that are orthogonal to the type system, `bool` and `char` are different, distinct types and if you specialize a template for T<bool>, it won't apply to `char` unless a conversion happens, and if it does so, it is still operating on `bool`, not char - it is constructing a type from another, the fact this happens is simply hidden from you, like Java and boxing (which ironically is an implicit conversion).

The Java delegates pretty much everything to the JVM, and that's reflected in the language design. Java is a simple language that does not do a lot at compile time, relying on runtime facilities to mitigate these shortcomings. See for instance how everything can always decay to a reference to Object, implicitly, everywhere, requiring casts (i.e. runtime assertions) to restore type safety - that's basically a safer `void*`.

1995's Java was clearly too limited, I understand they wanted a fresh start from the ugliness of '90s C++, but they straight removed too much for the sake of simplicity. The current crop of languages, which largely rejected the Java model is kind of a symbol of what went wrong with Java, IMHO.

The fact certain features had been "hacked" on top of the language using what was already there (see generics, boxing, ...), often introducing features that act like "magic", and can't be overridden by the user is bad, and shows how limited the original language was. The same way you can't override operators, you can't define custom boxing rules for your types (mostly because you won't be able to define custom value types until Valhalla is released).

Modern C++ allows you to write safe and solid code using compile-time features and the type system. While stuff like <type_traits>, SFINAE, template metaprogramming and such are definitely not "nice", they are extremely powerful and if used correctly eliminate completely certain issues from ever happening. If you only use smart pointers, references, containers, moves and by-value semantics you won't get crashes from nulls, ever. You won't have memory leaks, and after lots of fighting with the compiler, there's a high chance your code will work straight away (unless you messed up the logic). This is not that far from Rust, as far as my experience goes - I still hope for Rust to mostly replace C++ in the end, but for now C++20 is a very solid substitute and a good choice (and feels much more modern and powerful than Java could or has ever been).

Re:Google broke a conditional statement that verifies passwo... by GoblinSlayer on Friday July 23, 2021 @07:56AM (#27929680)
All versions of C++ inherit type system from C and keep it for backward compatibility. Indeed you can opt into a stronger dialect with right compiler flags, but this is used as widely as Prolog, because the rest of ecosystem uses an incompatible dialect and will fight against you. C++20 is a substitute of C++17, not of other languages.
Re:Google broke a conditional statement that verifies passwo... by qalmakka on Friday July 23, 2021 @08:37AM (#27929985)
The desire of maintaining compatibility with C at all cost is both the main selling point of C++ and the source of almost all of its madness. C was full of weird quirks (null terminated strings, enums that decayed to int, char* that could represent arbitrary data, weird syntax inherited from B, nonsensical arrays, ...) but its simplicity has always kinda kept everything down to a tameable level of chaos.

C++ took this quirky base and pushed it (abused it?) in ways that go way beyond what can be considered "sane"; see for instance the bajillion ways operator new() can be redefined, the fact there are at least 10 ways to initialize something, or the fact that features can be _discovered_ and not designed (like CRTP). Still, this wealth of features together with the unwavering (and arguably masochistic) Herculean efforts of the ISO C++ committee to modernize the language make it, by far, one of the most flexible languages around. Every single time I use C++ I discover a new amazing way to do something that had never crossed my mind; call me crazy, but I think this makes programming fun, a detail that is often (wrongly) neglected.

Re:Google broke a conditional statement that verifies passwo... by pjmlp on Friday July 23, 2021 @07:49AM (#27929629)
I just wish there would be a -fsafe compiler flag instead of having to deal with all the sanitizers and debug mode flags, but it is what it is.
Re:Google broke a conditional statement that verifies passwo... by asddubs on Friday July 23, 2021 @03:22PM (#27934580)
you can even use it for rvalues!
Re:Google broke a conditional statement that verifies passwo... by CobrastanJorji on Thursday July 22, 2021 @04:13PM (#27923728)
Forgive my poor C++, but has_value() sounds like a bool, and empty() sounds like a bool. Why wouldn't "bool1 & bool2" work correctly?
Re:Google broke a conditional statement that verifies passwo... by dataflow on Thursday July 22, 2021 @04:17PM (#27923785)
Dereferencing via key_label_-> has undefined behavior when !key_label_.has_value(), so the compiler treats that case the same as if key_label_.has_value(). Or to put it another way, the compiler reasons that key_label_ must have had a value (since you dereferenced it), and thus optimizes out the check for `has_value()` (since clearly it was unnecessary).
Re:Google broke a conditional statement that verifies passwo... by khazhoux on Thursday July 22, 2021 @08:24PM (#27925954)
I don't think that's right. It seems far-fetched that the compiler would know that accessing key_data->label() implies that k_d->has_value() == true

I believe the explanation is:

   A && B : compiler will evaluate B only if A==true

   A & B : compiler will evaluate both A (safe) and B (unsafe), then perform bitwise operation
Re:Google broke a conditional statement that verifies passwo... by dataflow on Friday July 23, 2021 @04:09PM (#27935033)
No, it's not far-fetched, this is a pretty well-known optimization.

https://blog.regehr.org/archives/970

Re:Google broke a conditional statement that verifies passwo... by fouric on Thursday July 22, 2021 @04:22PM (#27923827)
Ahhh, so it was a problem with lazy evaluation (and the lack thereof when using &), and not type coercion, like I initially thought.
Re:Google broke a conditional statement that verifies passwo... by dataflow on Thursday July 22, 2021 @04:30PM (#27923910)
Yeah it has nothing to do with type coercion. I'm baffled a linter doesn't catch this though. & for bools should just be prohibited altogether. If people really want & for bool, they can just cast to an integer type and use & with that (which generates its own warnings appropriately).
Re:Google broke a conditional statement that verifies passwo... by gpderetta on Thursday July 22, 2021 @04:51PM (#27924159)
the problem is that bitwise & and | are routinely used for their non-shortcircuiting behaviour in boolean expressions, so it is hard for the compiler to flag this as an error.

Many linters and static analysis tools do flag them though as these days it is not considered good practice.

Re:Google broke a conditional statement that verifies passwo... by anyfoo on Thursday July 22, 2021 @05:06PM (#27924343)
Why would you even need non-shortcircuiting behavior in boolean expressions? Because either side of the operator has side effects that you want to happen unconditionally? Please just write it out as an extra statement then instead of hammering it into place with an implicit coercion to an integer type only so you can abuse bitwise AND and OR only to force that side effect to... you can see why this is probably not the most elegant idea.
Re:Google broke a conditional statement that verifies passwo... by MauranKilom on Thursday July 22, 2021 @08:23PM (#27925948)
What I would like to write in unit tests:

    for (auto x : y)
      ok &= check(x);
That gets you angry messages from static analysis, so you probably have to write (since there is no corresponding assignment operator)

    for (auto x : y)
      ok = ok && check(x);
...except now you don't actually perform checks after the first failure. That may or may not be intentional (or even confusing - depending on logging). What you'd really need to write to preserve the original logic is

    for (auto x : y)
      ok = check(x) && ok;
Now the `&& ok` is much easier to miss (both in writing and reading) and the intent is much less clear.

I really do wonder why the standard doesn't just specify the behavior of bool & bool. Is it just because of holdover from C?

Re:Google broke a conditional statement that verifies passwo... by dataflow on Thursday July 22, 2021 @11:08PM (#27926751)
> I really do wonder why the standard doesn't just specify the behavior of bool & bool.

Confused about your question. Did you have a typo? bool & bool is valid in C++.

Re:Google broke a conditional statement that verifies passwo... by thaumasiotes on Friday July 23, 2021 @01:42AM (#27927591)
I'm guessing the question is related to this complaint:

> What I would like to write in unit tests:

> ok &= check(x);

> That gets you angry messages from static analysis

Re:Google broke a conditional statement that verifies passwo... by dataflow on Friday July 23, 2021 @01:45AM (#27927608)
That has nothing to do with the standard though? The behavior is well-defined, it's just compilers warning about use of & tending to be error-prone (rightly or wrongly).
Re:Google broke a conditional statement that verifies passwo... by gpderetta on Friday July 23, 2021 @09:33AM (#27930460)
I lost track how many times I have been bitten by the ok = ok && ... trap.
Re:Google broke a conditional statement that verifies passwo... by slavik81 on Thursday July 22, 2021 @05:30PM (#27924584)
Matt Godbolt gave an example of a significant performance hit caused by unnecessary short-circuiting in his CppCon 2019 talk[1]. EDIT: Deleted tangent.

[1]: https://youtu.be/HG6c4Kwbv4I?t=45m

Re:Google broke a conditional statement that verifies passwo... by thaumasiotes on Thursday July 22, 2021 @07:16PM (#27925478)
This example is interesting enough that it deserves to be written up for convenience. The reason there is a performance hit is that the example involves a lot of mispredicted branches.

The setup is that we have a large number of tiny triangles, we cast a ray in a random direction, and we want to detect whether it intersects any of the triangles. The summarized code looks like this:

  for (/* all triangles */) {
    auto u = calcU(/*...*/);
    if (u < 0 || u > 1) {
      continue;
    }
    auto v = calcV(/*...*/);
    if (v < 0 || u + v > 1) {
      continue;
    }
    auto dist = calcD(/*...*/);
    if (dist < nearest) {
      nearest = dist;
    }
  }
So what's happening?

We calculate the (x,y) coordinates of the point where our ray intersects the plane in which the triangle lies.

We convert those (x,y) coordinates to (u,v) coordinates, where the vectors u and v are parallel to two sides of the triangle. (And equal in length.)

In our transformed (u,v) space, determining whether a point lies inside the triangle is very easy. With the origin at the corner of the triangle from which the u and v sides emanate, a point is out of bounds if its u-coordinate lies outside the interval [0, 1], or if its v-coordinate lies outside [0, 1-u]. That's what the ifs after calcU and calcV are checking. When we detect that a point is out of bounds, we move on to the next triangle.

The triangles are small and the ray is random, so the intersection of the ray with the plane will strike at a random point. It is almost always the case that the point will lie outside the triangle. This means that the full conditional (u < 0 || u > 1) will almost always be false.

But the two subconditions u < 0 and u > 1 will each be true 50% of the time. They are individually impossible to predict, which causes branch prediction on the first one, u < 0, to fail about 50% of the time. But they are jointly easy to predict. There is a huge performance gain from switching to (u < 0 | u > 1) -- in this case, 50% of the time we will do the work of calculating whether u > 1 even though we didn't have to. But the reward we get for that extra work is that branch prediction drops from a 50% failure rate (actually 45%) to a very low failure rate.

Including the v-coordinate makes the full check, ((u < 0) | (u > 1) | (v < 0) | (u + v > 1)), even more easy to predict. We've decided to guarantee that we will always do the full amount of work, and most of it is unnecessary. But it's easier to do 2x or more the amount of work and test a condition that fails consistently than to do less work and keep having to clear the instruction pipeline.

Re:Google broke a conditional statement that verifies passwo... by thaumasiotes on Friday July 23, 2021 @02:02AM (#27927698)
> Why would you even need non-shortcircuiting behavior in boolean expressions? Because either side of the operator has side effects that you want to happen unconditionally?

Interestingly, the example provided by slavik81 is able to tolerate non-shortcircuiting behavior specifically because no side effects are involved. It's more of a case of "we don't care about the result of this work, but we have to do it anyway, because it's better to do a lot of extra work concurrently than to do only the necessary work sequentially." And doing the extra work is OK because it doesn't have any side effects.

If side effects were involved, you'd be stuck needing to short-circuit despite the fact that it's slower.

There are also areas in cybersecurity where you'd like the time taken for some operation to be insensitive to the input; short-circuiting is bad there too.

Re:Google broke a conditional statement that verifies passwo... by anyfoo on Friday July 23, 2021 @03:14PM (#27934493)
It's usually wrong to assume that expressions that ultimately have the same effect (such as a || b and a | b when both a and b are simple booleans, so no side effects) will make the compiler generate different code depending on which variant to use.

The compiler knows that both variants resolve to the same result with no side effects, so it should try to generate whatever code is more efficient. Depending on several factors, that may be machine code that effectively exhibits short circuit behavior or not, for either expression (so even a|b might end up having a short circuit on the lowest level).

This would be different if you, e.g., sprinkle some volatile keywords (which effectively introduces side effects), but then you'd probably still want to take more care and split the expressions up, unless you really don't care about the order of your forced memory accesses (i.e. if I recall correctly, there is no guarantee that a|b will access a first, then b). And that's not even going into barriers.

Re:Google broke a conditional statement that verifies passwo... by josefx on Friday July 23, 2021 @12:43AM (#27927287)
Reduced unit test complexity? Short circuiting implies more branches, more branches means more tests for 100% coverage.

Of course for that to be a downside someone would have to write tests for security critical code, which obviously did not happen.

Re:Google broke a conditional statement that verifies passwo... by snovv_crash on Friday July 23, 2021 @01:39AM (#27927583)
That is just gaming your coverage stats, there are still the different branches they just aren't visible now.
Re:Google broke a conditional statement that verifies passwo... by thaumasiotes on Friday July 23, 2021 @01:49AM (#27927631)
That's not true.

Compare `( a() || b() || c() ) ? yes() : no()` to `( a() | b() | c() ) ? yes() : no()`.

In the second case, there are two paths through the code:

  a()
  b()
  c()
  yes()

  a()
  b()
  c()
  no()
But in the first case, there are more paths:

  a()    /* true */
  yes()

  a()    /* false */
  b()    /* true */
  yes()

  a()    /* false */
  b()    /* false */
  c()    /* true */
  yes()

  a()    /* false */
  b()    /* false */
  c()    /* false */
  no()
That is because there are fewer branches in the second statement (just one) than there are in the first statement (three).
Re:Google broke a conditional statement that verifies passwo... by snovv_crash on Friday July 23, 2021 @09:03AM (#27930172)
So, it tests that you're running yes() and no(). But it doesn't test that your choice to use 'a()|b()|c()' for your condition was correct, instead of, for example, 'a()&b()&c()' or even '(a()&b())|c()' because you didn't test all the combinations. Using bitwise instead of logical operations hides this in your branch coverage report.
Re:Google broke a conditional statement that verifies passwo... by thaumasiotes on Friday July 23, 2021 @04:22PM (#27935167)
You are not attempting to have branch coverage; you are attempting to cover the space of possible inputs.
Re:Google broke a conditional statement that verifies passwo... by snovv_crash on Saturday July 24, 2021 @05:08PM (#27944500)
You're trying to check that all of your logic is correct. That's the point of doing tests. If your test doesn't check for certain input combinations, then you haven't tested your logic completely.

The point of branch coverage is to show when you missed input combinations for your logic. Artificially running all of the branches and then throwing away results just gives you a false sense of security about how much of your logic you covered.

I mean, technically, using bitwise instead of short-circuiting logic doesn't have branches at an assembly code level. But this is pedantry because we're actually trying to check the logic is correct, not that our compiler can correctly translate && into the same Boolean result as &.

Re:Google broke a conditional statement that verifies passwo... by GoblinSlayer on Friday July 23, 2021 @06:37AM (#27929180)
The code is correct if you hit yes() and no() correctly depending on three conditions. There are 8 possibilities in both cases and thus you need 8 tests in both cases. Shortcircuiting is optimization, it doesn't reduce complexity of the logic.
Re:Google broke a conditional statement that verifies passwo... by thaumasiotes on Friday July 23, 2021 @04:21PM (#27935153)
That is a concern, but it's not one related to how many branches exist in the code.

"How did we get here?" and "Are we in the right place?" are distinct questions.

Re:Google broke a conditional statement that verifies passwo... by GoblinSlayer on Friday July 23, 2021 @04:33AM (#27928507)
When you check for error conditions shortcircuiting is unlikely and thus useless.

if(error1|error2)abort();

Re:Google broke a conditional statement that verifies passwo... by anyfoo on Friday July 23, 2021 @03:03PM (#27934404)
But it semantically resolves to the exact same, and so the compiler will likely treat it the same and optimize for whatever makes most sense. This may both make a written "a|b" short-circuiting, and a written "a||b" non-short-circuiting, as long as the result stays the same (which for simple bool a,b it always does).
Re:Google broke a conditional statement that verifies passwo... by dataflow on Thursday July 22, 2021 @04:54PM (#27924195)
> & and | are routinely used for their non-shortcircuiting behaviour in boolean expressions

Really? I can't recall a single case of this with 'bool' in any codebase in my recent memory. I only see it with integers. And even if it's somehow routine for your codebases with bool (why?!), surely it's not routine inside a conditional expression, so at least they can prohibit it there?

Re:Google broke a conditional statement that verifies passwo... by kevin_thibedeau on Thursday July 22, 2021 @07:12PM (#27925455)
Whenever I see it I assume it's a typo. If it was truly intentional I would expect a comment pointing out why it's needed.
Re:Google broke a conditional statement that verifies passwo... by kbelder on Thursday July 22, 2021 @04:59PM (#27924246)
I think this is a unpopular opinion, but I consider taking advantage of short-circuiting in boolean operations to be a code smell. At least for me, it seems very fragile and I'd much rather break the conditional logic out explicitly.

But I like to write as much like assembly as I can in every language. Each line of code should do one and only one thing.

Re:Google broke a conditional statement that verifies passwo... by saagarjha on Thursday July 22, 2021 @07:13PM (#27925461)
Short circuiting boolean operators are very useful, and not something I would consider a code smell. They let constructs like this work, which are very common in most codebases:

  if (foo && foo->bar) {
      // whatever
  }
An operator that did not short circuit would have undefined behavior because it might dereference a NULL pointer.
Re:Google broke a conditional statement that verifies passwo... by JonathonW on Thursday July 22, 2021 @07:33PM (#27925591)
If you're going for "each line of code should do exactly one thing", you'd probably prefer that as

    if(foo) {
      if(foo->bar) {
        //whatever
      }
    }
separating out the null check and the actual conditional. More lines of code and more nesting, yes, but, if you're trying to strictly adhere to a one thing/one line principle, you probably don't care.

Short-circuit 'or' is a little harder to avoid (if you specifically want the short-circuit behavior), since you'd have to duplicate the code in the body of the if. But that doesn't come up as often IME.

Re:Google broke a conditional statement that verifies passwo... by kbelder on Thursday July 22, 2021 @08:04PM (#27925824)
Yep, I'd prefer that option, despite its wordiness. Obviously this depends a lot on individual preferences, and in this simple example it really doesn't make a lot of difference.

I imagine the compiler spits out pretty similar code either way. It's more just a recognition of my own limitations... I'm a lot less likely to screw up something up, the more explicitly it's written out.

When I was a younger man, I wouldn't have bothered.

Re:Google broke a conditional statement that verifies passwo... by zarzavat on Thursday July 22, 2021 @09:46PM (#27926384)
The problem with that code and the reason that it is often considered bad C++ practice is that it is very easy to accidentally move the inner conditional outside of the outer conditional, thus creating undefined behaviour.

Putting the null check in the same line as the usage means that it is much harder to separate them accidentally.

Re:Google broke a conditional statement that verifies passwo... by bobbyi_settv on Friday July 23, 2021 @02:32PM (#27934089)
That technique doesn't work (as well) when you want a single "else" block that is used when either of the conditions is false, which I think is pretty common for this sort of conditional
Re:Google broke a conditional statement that verifies passwo... by dataflow on Thursday July 22, 2021 @05:04PM (#27924318)
I used to only put short-circuits when I really needed short-circuit behavior, thinking it improved readability. But after getting by the implicit type conversions over and over (as well as nags from every compiler) I just decided it was a bad idea in C++. I'd still do it in a safer language, but in C++ I'm convinced you should just use && even when you only need & for bools.
Re:Google broke a conditional statement that verifies passwo... by xmprt on Thursday July 22, 2021 @04:53PM (#27924186)
So instead of short circuiting like that code should when it uses &&, it instead makes an assumption about the first part of the boolean expression because otherwise the code would have undefined behavior?
Re:Google broke a conditional statement that verifies passwo... by dataflow on Thursday July 22, 2021 @04:59PM (#27924249)
Yeah. More specifically, it just inserts whatever behavior it likes for the undefined scenario, which in this case is "the same behavior as in the defined scenario".
Re:Google broke a conditional statement that verifies passwo... by ddalex on Friday July 23, 2021 @03:03AM (#27927996)
I am utterly confused. How would the compiler know that has_value() guarantees that the ->label dereferencing work, since this is a bitwise operation ?
Re:Google broke a conditional statement that verifies passwo... by dataflow on Friday July 23, 2021 @03:06AM (#27928022)
I would imagine has_value is checking to see if a pointer is NULL, and -> is dereferencing that same pointer. When the optimizer sees the two together it realizes the former is useless.
Re:Google broke a conditional statement that verifies passwo... by ddalex on Friday July 23, 2021 @06:43AM (#27929221)
by this logic the compiler would optimize any short-circuiting because it KNOWS the programmer WOULD NEVER deference an invalid pointer
Re:Google broke a conditional statement that verifies passwo... by jhasse on Friday July 23, 2021 @08:55AM (#27930116)
no, & is not short-circuiting
Re:Google broke a conditional statement that verifies passwo... by myko on Thursday July 22, 2021 @04:38PM (#27923996)
Would this optimization not have been on the beta/canary channel? I assumed they were but perhaps not since this was not caught.
Re:Google broke a conditional statement that verifies passwo... by dataflow on Thursday July 22, 2021 @04:43PM (#27924063)
I don't know how their builds work or where their templates are instantiated but it's possible that the compiler doesn't see this optimization until LTO and that they don't do LTO until stable releases? It would seem strange though, I'd have thought beta would have LTO.
Re:Google broke a conditional statement that verifies passwo... by anyfoo on Thursday July 22, 2021 @04:50PM (#27924148)
Yeah that would be a very weird choice. LTO itself can have bugs, or (as we speculate here) unmask existing bugs. Plus, even that aside, you'd hopefully test exactly the build that you will release before you release it.

As I wrote in another comment, this could still be the result of a freak accident and not have shown up in testing, though (but since I know nothing about the process or the code there, it could be anything).

Re:Google broke a conditional statement that verifies passwo... by kevinmgranger on Thursday July 22, 2021 @04:17PM (#27923779)
If I had to guess, the second expression depends on the first being true. So if `has_value()` is false, perhaps `key_data_->label()` is undefined behavior.
Re:Google broke a conditional statement that verifies passwo... by Cthulhu_ on Friday July 23, 2021 @04:30AM (#27928497)
In other languages, booleans are their own values (iirc in C/C++ they're aliases for 0/not-0) for which the `&` operand is simply not implemented.

There's also linters and other quality control analyzers that will warn on a bitwise operator on booleans.

Re:Google broke a conditional statement that verifies passwo... by account42 on Friday July 23, 2021 @09:03AM (#27930173)
C++ has separate true and false values of type bool, but they are implicitly convertible to int.
Re:Google broke a conditional statement that verifies passwo... by jhasse on Friday July 23, 2021 @08:57AM (#27930123)
That's C, in C++ booleans have their own type, too (called bool).
Re:Google broke a conditional statement that verifies passwo... by gmfawcett on Thursday July 22, 2021 @04:33PM (#27923952)
This is one of those times when, for all its verbosity, Ada got it right. For boolean conjunction you must choose between writing "A and B", or "A and then B". The "and then" version is short circuiting, while the bare "and" version is not.
Re:Google broke a conditional statement that verifies passwo... by gene91 on Thursday July 22, 2021 @05:22PM (#27924508)
This is a typo of missing an ampersand. If the author were writing Ada, it would have been a typo of missing a “then”. How is it different?
Re:Google broke a conditional statement that verifies passwo... by Cthulhu_ on Friday July 23, 2021 @04:31AM (#27928500)
It's different because in C it changes a boolean comparison to a bitwise one. Is Ada's `and` a bitwise and?
Re:Google broke a conditional statement that verifies passwo... by gpderetta on Friday July 23, 2021 @05:12AM (#27928718)
For bool there is no difference between bitwise and and logical and.

There is a difference between short-circuiting and non short-circuiting and, hence the distinct operators.

Re:Google broke a conditional statement that verifies passwo... by thesuperbigfrog on Friday July 23, 2021 @12:57AM (#27927373)
The equivalent Ada code does not exist as the Ada boolean type only has a logical AND operator (no bitwise operations exist):

http://www.ada-auth.org/standards/12rm/html/RM-A-1.html#I538...

Re:Google broke a conditional statement that verifies passwo... by shawnz on Thursday July 22, 2021 @04:40PM (#27924028)
Visual Basic also has this distinction (but the keywords are "And" and "AndAlso")
Re:Google broke a conditional statement that verifies passwo... by shawnz on Thursday July 22, 2021 @04:51PM (#27924164)
Other than this particular edge case it's not obvious to me why bitwise operators shouldn't be applicable to boolean values. Aren't they just single-bit vectors?

Of course it makes sense that logical operators wouldn't be applicable to numeric types, but why the reverse?

Re:Google broke a conditional statement that verifies passwo... by qalmakka on Thursday July 22, 2021 @06:22PM (#27925069)
If you stop integer values from being implicitly convertible to booleans, you break the language and its compatibility with C.

The inverse is debatable, though. I honestly don't see why someone would do bitwise operations on boolean, unless they really wish to die a slow death from thousand cuts. Integer promotion rules make even the simplest operations a wild mess, and there's nothing in the standard that prevents bool from having a sizeof equal to int (thus further complicating everything).

It might be sensible for newer language revisions to consider deprecating certain operators from being applied to bool, given that there is a strong change that 99% of the time their use is not on purpose, but I guess it depends on how much disruptive such change would turn out to be.

Re:Google broke a conditional statement that verifies passwo... by shawnz on Thursday July 22, 2021 @06:36PM (#27925194)
I don't think the other poster was imagining a language that retained compatibility with C, but rather a new language altogether. Of course it would be impossible to change this aspect of the language if retaining compatibility with C was a requirement.

> I honestly don't see why someone would do bitwise operations on boolean

For example, you might want the behaviour shown here of not short-circuiting. Or you might want to create a bitwise function that also allows calling on single-bit (i.e. boolean) values.

Re:Google broke a conditional statement that verifies passwo... by qalmakka on Friday July 23, 2021 @02:47AM (#27927902)
> you might want the behaviour shown here of not short-circuiting. Or you might want to create a bitwise function that also allows calling on single-bit (i.e. boolean) values.

In both cases, I think the risk-benefit ratio is way too skewed towards the risk of creating ugly, hard to detect bugs. When I don't want short circuiting from happening, I just assign the RHS of the expression to a variable beforehand; if I want a boolean to become an integer, I make it explicit with a cast.

Sometimes, using certain C and C++ debatable features feels like attempting to shave yourself using a dagger. The fact you could do that doesn't mean you should, or even that it is a good idea.

Re:Google broke a conditional statement that verifies passwo... by gpderetta on Friday July 23, 2021 @05:08AM (#27928696)
You could make the opposite argument that short-circuiting is the surprising behavior [1] and you should make it explicit with an if.

[1] and in this very thread many people were actually surprised by it!

Re:Google broke a conditional statement that verifies passwo... by qalmakka on Friday July 23, 2021 @06:57AM (#27929321)
Short circuiting for logical operators has existed at least since the first C versions in the early '70s. It's maybe not intuitive, it's probably a crummy idea, but that's how basically everything based on C works (including modern languages like Go and Rust), so there's not that much that can be done about that.

Also, after seeing how weird JavaScript is in comparison, I have to say that C++ definitely isn't the strangest kid in the block when accounting for weirdness and unintuitive behaviours.

Re:Google broke a conditional statement that verifies passwo... by phkahler on Thursday July 22, 2021 @05:22PM (#27924505)
>> Other than this particular edge case it's not obvious to me why bitwise operators shouldn't be applicable to boolean values.

That is a really good question. At some point they decided that true=1 and false=0 but I'm not sure how deep that goes. In particular what does ! actually do in this context?

Re:Google broke a conditional statement that verifies passwo... by gpderetta on Friday July 23, 2021 @05:09AM (#27928702)
In what context? Unless overloaded ! coerces its operand to bool and returns the negation.
Re:Google broke a conditional statement that verifies passwo... by wyager on Thursday July 22, 2021 @04:40PM (#27924027)
The most general solution here is to use algebraic types and pattern match on the value being “None” or “Some data”.
Re:Google broke a conditional statement that verifies passwo... by tialaramex on Thursday July 22, 2021 @09:28PM (#27926295)
Certainly I find

  if (key_data_.has_value() && !key_data_->label().empty())
    return key_data_->label();
to be less readable than:

  if let Some(label) = key_data_ {
    label
  }
It's notable that people complain Rust adds too many odd punctuation marks, and yet in this example it's C++ with an exclamation mark, question marks, and two different structure member operators (dot and arrow) while Rust just does the pattern match.
Re:Google broke a conditional statement that verifies passwo... by Cthulhu_ on Friday July 23, 2021 @04:33AM (#27928509)
It's not, because that would involve re-engineering and re-writing millions of lines of code.

The simpler solution is to fix this gap in their automated testing. Another one is to configure a linter to error on bitwise operations on boolean values.

Re:Google broke a conditional statement that verifies passwo... by dylan604 on Thursday July 22, 2021 @04:17PM (#27923788)
That so sounds like an error I would make and not some superDev working at the Googs making around 4x the amount of money I make.
Re:Google broke a conditional statement that verifies passwo... by myko on Thursday July 22, 2021 @04:38PM (#27924004)
They're just people. If you want to get in you probably could, with some effort.
Re:Google broke a conditional statement that verifies passwo... by anyfoo on Thursday July 22, 2021 @04:41PM (#27924043)
Not sure why you think a "superDev" would be less susceptible to simple typos?
Re:Google broke a conditional statement that verifies passwo... by SilasX on Friday July 23, 2021 @12:20AM (#27927163)
The superDev would be; the linters and test suite (that said devs should be enforcing and maintaining) shouldn’t be.
Re:Google broke a conditional statement that verifies passwo... by grishka on Thursday July 22, 2021 @04:37PM (#27923994)
Certainly won't compile in Java.
Re:Google broke a conditional statement that verifies passwo... by shawnz on Thursday July 22, 2021 @04:51PM (#27924171)
In fact you can apply the single ampersand & operator to booleans in Java, and just like in the example here it has the same behaviour as && but with no short-circuiting.
Re:Google broke a conditional statement that verifies passwo... by grishka on Thursday July 22, 2021 @05:23PM (#27924514)
Huh. I didn't know that.
Re:Google broke a conditional statement that verifies passwo... by taeric on Thursday July 22, 2021 @04:59PM (#27924244)
Oddly... It would? Try:

    Map<String, Boolean> map = ...
    if (map.containsKey("hello") & map.get("hello")) { ...