4 ms·
Explicit casts are problematic. Here's an example: int32 a; int16 b; //... b = (int16)a; Later you decide to change b to int32. int32 a; int32 b;
by flowerlad 5y ago
Explicit casts are problematic. Here's an example:
int32 a;
int16 b;
//...
b = (int16)a;
Later you decide to change b to int32.
int32 a;
int32 b;
//...
b = (int16)a;
Now you have a bug. If you didn't have that explicit cast the program would have worked as expected.
- gameswithgo 5y agothe first program might not have worked as expected though.
- klodolph 5y agoBut, that's a good example of why implicit casts are bad! b = (int16)a; This contains two casts... one explicit cast to int16, and one implicit cast back to int32. In languages without implicit casts, this would be an error.
- astrange 5y agoMany languages "without implicit casts" e.g. Java still have this problem because they allow widening casts. I don't think it makes sense to ban them in a language with powerful enough checks, like dependent types. If you have two variables and one is typed "int 1-10" and the other is typed "int 1-5", and it fails at runtime if it doesn't fit in the destination range, why do you need to type something that says you really meant to assign one to the other? Just assign it.
- klodolph 5y ago> Many languages "without implicit casts" e.g. Java still have this problem because they allow widening casts. I'm reading this as, "Many red boxes are blue circles." If the language allows implicit widening casts, it has implicit casts. I don't think more powerful checks are necessary. It's just that the implicit conversions in C are a bit wild, and they result in unexpected behavior and surprise programmers, and from experience, making all casts explicit is not such a burden (except for stuff like char ptr -> const char ptr). I think the fantasy here is simple... as much as we want to explore new ways to make safe programs with better type systems and runtime checks, there is still some design space near C which is safer but not really more complicated.
- ChrisSD 5y agoTbh, I don't think you're the first person to think that but the trouble with making a "safer C" is that it's not C. Or to be more precise, it looks like C but isn't C compatible. This has ended up killing most attempts. Apparently nobody actually wants an almost-C language (alternatively, nobody has yet managed to successfully market one). There seems to be an uncanny valley effect with C-like languages. The best you can do is have non-standard compiler extensions on top of ISO C.
- klodolph 5y agoNo, this approach is more common and successful than you might think. We're not talking about making an entirely new language which is incompatible with C. You adopt a style guide, an accompanying static analysis tool, and maybe add some annotations to your source code. Your code is still C-compatible and you can still use the same compilers. Static analysis of general C programs is quite difficult, and turning on an analyzer for an existing codebase typically results in obscene numbers of false positives. However, if you pair a static analyzer with a strict style guide which restricts the language, you can make the static analyzer much more powerful and useful. This could be MISRA, it could be a formal verification system, or it could be something else entirely.
- astrange 5y ago> I'm reading this as, "Many red boxes are blue circles." If the language allows implicit widening casts, it has implicit casts. The problem is that people state things like "Java doesn't have implicit casts for correctness." But then it does have implicit casts, so now is there still correctness? Another case is Haskell, where the wiki tells you: > Conversion between numerical types in Haskell must be done explicitly. This is unlike many traditional languages (such as C or Java) that automatically coerce between numerical types. But what this actually means is instead of `a = b` you do `a = fromInteger b`. This is obviously also an implicit cast, because Haskell has type inference. So again, you're not writing a proof that your conversion is correct. You're just writing a different, longer "yes I really mean to assign this" statement.
- 5y ago
- oconnor663 5y agoI think the bug here is arguably also an implicit cast, from int16 back to int32. Languages that don't allow implicit casts at won't compile that last line.
- LambdaComplex 5y agoWouldn't the compiler stop your second example? You're trying to assign an int16 value to b, which is now an int32.
- zabzonk 5y agoNot in C.
- LambdaComplex 5y agoSounds like this is less "explicit casts are bad" and more "explicit casts are bad in C" then. Rust indeed errors out at compile time for the reason I stated: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=ae7728b22b223249108ce460c3b43db6 https://play.rust-lang.org/?version=stable&mode=debug&editio...
- zabzonk 5y ago> Now you have a bug. Weeell, maybe not. I agree that whenever I see a cast, I think "WTF?", but maybe you want what the cast does?
- aw1621107 5y agoI think it’s less a problem with explicit casts and more a problem of insufficient expressivity. If what you wanted was “cast to the type of b”, then something along the lines of C++’s decltype would be better: b = static_cast<decltype(b)>(a); And as other commenters have pointed out, if implicit widening is disallowed that would also prevent the potential bug.
- astrange 5y agoThe problem with mandating this is that it doesn't really express anything - the semantics are the same as `b = a;`. And there's a cost because it's quite verbose. If what you want to express is "I know b and a have different storage sizes", that could be useful, but it doesn't do that because eg if you typo `b` for `a`, then `b = static_cast<decltype(b)>(b);` is still accepted.
- aw1621107 5y ago> The problem with mandating this is that it doesn't really express anything - the semantics are the same as `b = a;`. And there's a cost because it's quite verbose. Sure, but at least the problem is back to "should conversions/casts be implicit or explicit?", rather than "I cannot do what I want with explicit casts". > If what you want to express is "I know b and a have different storage sizes" You may not even know this (e.g., in generic code), and if you did want to ensure different storage sizes specifically, then you want a (static) assert. > eg if you typo `b` for `a`, then `b = static_cast<decltype(b)>(b);` is still accepted. That would also apply to the version with implicit casts/conversions, wouldn't it?
- afr0ck 5y agoIf C lets you shoot yourself in the foot, it doesn't mean that you should do it! If you cast something then you need to take a moment to think about it first and check if it makes sense and whether it is really needed.