5 ms·
In a better language this mistake can't happen anyway. One of the things which too often gets missed when explaining why C++ is unsafe is that it's full of thes
by tialaramex 2y ago
In a better language this mistake can't happen anyway. One of the things which too often gets missed when explaining why C++ is unsafe is that it's full of these unnecessary footguns, there is no need to be able to get this wrong.
C++ gets this wrong for maximum drop-in compatibility with C, the classic "New Jersey Style" programming language where simplicity of implementation is prized over simplicity of use or correctness.
- prerok 2y agoDefine "better language". The duck typed languages all suffer the same problem. Even in Go we had a stupid problem where default json deserializer creates floats (when deserialized into any) and the number was high enough int64 where it lost precision. I mean, we can go at it all night long what pitfalls await in what language. Perhaps Rust is safest with its own pitfalls where you just can't do it safely (looking at you BST and use of Arc). Programming is full of such traps and only inexperienced engineers in a language would make such a mistake. This includes engineers with 20+ years of 1 year experience.
- jshier 2y agoIn this case, a language that doesn't support automatic numeric type conversions. For instance, in Swift, 1 / FRAMERATE would give you integer division if FRAMERATE was an Int, or Double/Float division if FRAMERATE was a float, as the 1 literal would be inferred to a compatible type for / if one existed. You would never see Int / Float, or an implicit conversion between numeric types.
- niborgen 2y agoNever worked with Swift before, but this checks out: https://swiftfiddle.com/mt5uptmbynbt7bi4jot7m5laum https://swiftfiddle.com/mt5uptmbynbt7bi4jot7m5laum Careful though, if you don't have :Float on ts it still gives 0.
- prerok 2y agoI don't understand the point of both replies... my point was that integer based division is preferred in all languages and the floating point must be somehow "forced" that one operand is float. The post I was replying to mentions that this sort of problem does not exist in "better languages" but my point was that it does. The problem here is that the code assigns an integer (result of division) to a float which is implicit "upgrade" in languages like C and C++ and required to be explicit in newer languages like Golang and Rust. My point, which I seem to have failed to make, is that careless programmers would (and do!) make a silly thing like: v := float64(operand1 / operand2) just to satisfy the compiler error. A common mistake for junior programmers but unforgivable (for some interpretations of unforgivable :) ) one for a senior.
- tialaramex 2y ago> integer based division is preferred in all languages What does this even mean? First of all, several languages have distinct "integer divison" and "floating point division" operators, so there's no sense in which integer is "preferred" in those languages, they're unrelated operations. Even allowing for your ignorance of such languages many modern languages do not have untyped constants, they're an attractive nuisance. If you don't have untyped constants then even if you're relying on implicit typing for constants (which I also don't like) you trip a mistake in the original expression anyway which is now unalike. This mistake only occurs in a language with all of: 1. A single division operator despite two distinct operations 2. Untyped constants 3. "Promotion" so that type mismatches just do something unexpected and compile anyway.
- gpderetta 2y agoSo you would have different, say, distinct division operators for each of u8, u16, u32, u64, u128 and their signed variant, for each floating point type, complex numbers (and all their underlying variants), quaternions, etc? You might quickly run out of operator soup.
- 2y ago
- lejoko 2y ago“only inexperienced engineers in a language would make such a mistake” — famous last words…
- jononor 2y agoPython (3) gets this right. Integer division is a separate operator: // vs /.
- prewett 2y agoBut the "better" languages have their own problems. UI calculations tend to need to mix int/float frequently, and the calculations can get fairly unreadable from all the casting (and I'm the sort that religiously casts to floats in C++ because I get burned on this). Swift, in particular, was particularly bad about this (Swift 5; I can't remember the details). Then there are things like `total / n` when calculating an average. Obviously you want `n` to be an int, because incrementing a float is a bad idea, but now you need to cast `n`, even though `total` is already a float, because they don't match. I tend to prefer the casting, because I had spending a bunch of time debugging 0s and NaNs, but sometimes it makes things look unnecessarily ugly and hard to read.
- robertlagrant 2y ago> Then there are things like `total / n` when calculating an average. Obviously you want `n` to be an int, because incrementing a float is a bad idea, but now you need to cast `n`, even though `total` is already a float, because they don't match. I don't know about other languages, but Python just lets you divide a float by an int, or vice versa, and it just always produces a float. Seems the most obvious thing to do.
- tuveson 2y agoI agree that implicitly promoting integers to floats (or implicitly changing any type) is a bad idea, but I don't think the C++ is uniquely bad in this regard. Java[1] and C#[2] both do this too. [1] https://godbolt.org/z/vE9n14a54 https://godbolt.org/z/vE9n14a54 [2] https://godbolt.org/z/aPa3P1Grc https://godbolt.org/z/aPa3P1Grc
- tialaramex 2y agoRight, certainly I don't want to single C++ out for this - I mentioned it because (a) the article we're talking about is describing a mistake the author found in some C++ code, and (b) I wanted to head off the inevitable call to blame C, yes, C++ does it because C does it (and that's probably why Java and C# do it too) but that's a choice and it's a bad choice. Implicit conversion is always a mistake. The price in terms of reduced clarity and extra mistakes is too high for the marginal convenience of less typing. I feel the same for boolean coercion even, which I know is more controversial than some of the really stupid C promotions, I do not believe in "truthiness". There's only one false, it's the constant false, it's not 0 or "" or 0.0 or an empty array or a null pointer or a billion other things, it's just itself and nothing else.
- tuveson 2y agoYeah I totally agree, it’s a bad design choice and the successors to C should not have copied it.
- nj5rq 2y ago> why C++ is unsafe is that it's full of these unnecessary footguns I don't see the "footgun". C and C++ allow you to perform divisions by integers. If you don't specify the decimals, it understands that they are integers. It's how it's meant to be. In my opinion, calling that a "footgun" is like saying using single quotes for characters is a "footgun" because someone could interpret them as strings. That's just not understanding the language.
- daymanstep 2y ago"just read the docs" is a fully general counter argument that can be used to justify arbitrary bad design decisions I think Python 3 did the right thing by having 1/3 equal 0.333 (a float) rather than 0. It's more intuitive for the / operator to always do standard division and when you want integer division then you use the // operator instead. It's more consistent than having / return a completely different result depending on whether one of the operand happens to be 3 instead of 3.0
- gpderetta 2y agoAre you saying that it is intuitive that 4/2 should return a floating point number? Or the type of the result should depend on the value? I would expect that no C or C++ programmer would find it intuitive
- tialaramex 2y ago> I would expect that no C or C++ programmer would find it intuitive My guess is that if instead C and C++ had two operators here you'd find C and C++ programmers fiercely defending this reality as the only correct choice. The tribalism particularly in C++ is very strong. There are a handful of accepted topics for disparagement, such as the std::vector<bool> specialisation but outside that any questioning of orthodoxy is not well tolerated.
- gpderetta 2y agoAside from the flame-baity strawman, I'm not sure for which behaviour you are exactly arguing for.
- Night_Thastus 2y agoDrop-in compatibility with C is incredibly useful. I can't tell you how many times I went "man I just need to do X" and there was a C library floating around that did exactly what I wanted. Most of C++ choices come with both positive and negative tradeoffs, despite what Rust users will say.