Hacker News new | ask | show | jobs
by steveklabnik 2230 days ago
Okay, so let's review the language's rules here:

* There are two modes for overflow checking: enabled, and default.

* If overflow checking is in "enabled" mode, overflow results in a panic.

* If overflow checking is in "default" mode, the results are two's compliment wrapping.

* Debug builds are "enabled" mode.

(There's a few other details, but this is good enough for our discussion. See https://github.com/rust-lang/rfcs/blob/master/text/0560-inte... )

Rustc implements this as follows:

* When debug_assertions is on, it's in "enabled" mode.

* Otherwise, it’s in “default” mode.

* -C overflow-checks turns on "enabled" mode, regardless of other settings.

This is completely consistent with the rules of the language. If these checks ever get cheap enough, rustc may even start to turn them on by default, which is also acceptable under these rules. We'll see if that ever happens, though.

1 comments

So let's review where we are right now. C++ left the entire thing undefined, which gave compilers the complete freedom to add flags that define e.g. wrap-around or trapping or other behavior. I suggested you can use such flags if you want. You complained about that and said it's "changing" language semantics... despite the fact that it's 100% consistent with the "rules of the language". You even went on to claim "we don't do that in Rust". All right. So I pointed you to a Rust compiler flag that changes the default wrap-around to a panic. Now you're saying that's not changing Rust's language semantics... and your defense is "it's consistent with the rules of the language"...?!
Undefined behavior is different from implementation defined behavior. Code that exhibits UB is not a valid program. Flags that take UB and define it are categorically different than flags that tweak various options, because flags that define UB expand the set of valid programs, where flags that tweak options do not.
Okay, you're very confused. You're getting it almost backwards.

Undefined behavior is behavior that the language does not define, not behavior that the implementation is prohibited from defining. That's why you can't treat it like (for example) a random-number generator. Implementations are well within their rights (i.e. 100% consistent with the language) to define previously-undefined behavior to be anything. They're also just as welcome to leave them undefined. Both are 100% consistent with the language and neither is "changing" the language semantics. No program that exhibited UB is going to misbehave somehow just because someone decided to define the behavior under UB. The semantics already allowed anything to happen. Whatever they define falls under "anything could happen".

Implementation-behavior is behavior that the the implementation is guaranteed to define. Like with UB, the implementation has freedom to choose a behavior. Unlike with UB, it is not allowed to leave that behavior undefined. So the program can be sure to have a well-defined output.

It is completely wrong to simultaneously say changing "wrap" to "crash" is "not changing semantics" and somehow "consistent" with the language rules, but that changing "undefined" to "wrap" is "changing semantics" and "not consistent" with the language rules. If the language wraps on overflow, then changing that to a panic is actively shrinking the set of valid programs; valid programs that used to behave one way now behave differently. (They crash!) The latter is merely expanding the set of valid programs; programs that had no rights to claim any behavior under UB now actually have a right to claim something under the implementation, but that doesn't change the behavior of previously-valid programs. They're still provided exactly the same guarantees they already were.

(P.S., UB isn't even a property of a program, but of an execution. But I'll leave that out since the simplified version is clearly confusing enough as-is.)

I do absolutely understand that UB does not prohibit implementations from defining something. That’s part of the core of what we’re taking about! I’m saying rustc chooses to never do so. C and C++ compilers do choose to do so. That distinction is what we’re talking about.

(As well as that overflow is UB in one language and not another, of course.)

No comment on everything else I wrote beyond that 1 sentence? Your positions are quite contradictory, which is what I've been trying to explain in the entire comment.
I just don't think we're going to get anywhere, but wanted to correct the assertion that I do not understand this aspect of UB.