5 ms·
Can anyone explain the reason why C or C++ compilers can't do this? Obviously the language specs allow you to do the unsafe thing, but suppose we add some "-Wre
by zrm 10y ago
Can anyone explain the reason why C or C++ compilers can't do this? Obviously the language specs allow you to do the unsafe thing, but suppose we add some "-Wreference-lifetime" flag to gcc that warns if it can't statically verify that a reference or pointer doesn't outlive the referenced object, and then compile everything with "-Wreference-lifetime -Werror" from now on.
What aspect of the language in particular makes that impossible? Or is it?
- simias 10y agoMy guess would be that in order to be safe you'd also have to seriously constrain other aspects of the language (like casts for instance). You'd probably have to introduce something like rust's "unsafe" to turn those checks off locally. You'd have to add additional syntax to manage lifetimes. Basically you'd reimplement Rust in C++. 99% of the C++ code out there wouldn't compile anymore and a lot of it would require significant re-architecturing in order to work with the new paradigm. Or more likely the vast majority of the codebase would keep working in "legacy" mode which wouldn't play nice with the safe portions of the code (since you'd have to consider all calls to the rest of the code as unsafe). Same thing with any external library not updated to be "safe". It's like the python 2 -> 3 transition, except a lot worse because it's significantly more complicated and probably can't be automated easily. The reason C++ was so successful is because of its backward compatibility (all the way back to C). I'm not sure it'd make a lot of sense to introduce such radical changes now. Especially given how incredibly huge the language is already.
- m1el 10y agoIn principle, nothing stops C++ compilers from implementing this feature. However, this - requires additional input from the programmer, such as lifetime parameters in Rust. - C and C++ don't have ADTs which help working with lifetimes A LOT (e.g. having Option<Box<T>> as nullable pointer). - will reject 99.9% of useful libraries and programs written in C. - would be equivalent to using Rust.
- lmm 10y agoFor the record C++17 does introduce std::variant. It's horribly cumbersome but it does at least exist.
- m1el 10y agoIt's horribly cumbersome AND it doesn't solve the same problem. // Rust let v: Result<i32, i32> = Ok(1); // std::variant (doesn't compile) std::variant<i32, i32> v = 1;
- wyldfire 10y agoI had to RTFM a bit to understand this example, so here's a more explicit description of this case for those playing along at home: AFAICT the idiom for Result<i32, i32> is a pair of "numerical-result-if-success"/"errno-if-failure". Seems like a great idea, allows us to not overload a simple integer result and end up ignoring the failure path by accident. "Ok(n)" would get assigned to the "numerical-result-if-success" and "Err(m)" would get assigned to the "errno-if-failure". I think this means that "v.unwrap()" would panic if it had been assigned "Err(m)", which is what most people would want/expect. AFAICT std::variant can't do overload resolution correctly when both of the union types are the same. I'll wager that if you use an aliased type it will still choke on this ambiguity. So if you wanted something similar in C++ maybe you'd have to wrap it so it's not POD?
- m1el 10y agoIt's not quite a "pair". It's a "tagged union" in C-speak, "enum" in Rust-speak and "sum type" in CS-speak. In this case, numerical result and errno will be located in the same memory, but have different tag.
- pjmlp 10y agoThe type system, you can do anything regarding memory access, for example using long for pointers and this code must still work as designed even with such switches. Microsoft and Google are working on static analysis tooling for this, regarding C++, but the tools require you make use of the right types. Also, like any tool not part of the language standard, its use is optional.