I propose that Go adds checked and unchecked keywords for arithmetic operations that function like those of C#. This is somewhat similar to the Go 2 error handling proposal.
This is related to #19624. If #19624 is accepted, then cases like hash64.go could be handled by wrapping the calculations in an unchecked block, which is a cleaner solution than anything I saw presented on #19624.
checked {
x := a * b
y := a + b
z := x^y
}
unchecked {
x := a * b
y := a + b
z := x^y
}
It would be difficult to allow checked and unchecked to be used on statements without breaking backwards compatibility or making it confusing. The possibilities that occur to me are A) not bothering (only supporting blocks), B) unchecked(a * b), or C) unchecked a * b.
To clarify, the keywords would not affect the compilation of function calls. For example, given f(x * y) * z, only the two multiplication operations would be affected. Nothing inside the function call would be affected.
This is a lot of mechanism to add for a relatively small part of the language.
cc @bcmills
It sounds like this would be better handled by a library for checked arithmetic.
The , ok syntax still seems clearer to me, and doesn't add any new keywords or AST nodes.
checked:
x := a * b
y := a + b
z := x^y
unchecked:
x, _ := a * b
y, _ := a + b
z := x^y
@bcmills is the comma ok approach discussed in another issue? I don’t recall. I have a few comments about it and I’d like to keep the discussion localized.
@josharian, the “comma, ok” proposal is #19624.
@bcmills If you write every operation as a separate assignment, then it doesn't matter much. But that's not what I would do.
checked, concise:
z := (a * b)^(a + b)
// ...
unchecked, concise:
unchecked {
z := (a * b)^(a + b)
// ...
}
unchecked, verbose:
x, _ := a * b
y, _ := a + b
z := x^y
// ...
If the calculation I'm doing is long and complicated, requiring every operation to be a separate assignment would drastically reduce readability.
@firelizzard18, under the current draft of #19624 you only need one assignment per expression tree, not one per subexpression. (There is some subtlety around subexpressions that cross function-call boundaries, but that is not applicable here.)
So the unchecked version would be:
z, _ := (a * b)^(a + b)
Let's move this discussion into #19624, as an alternative syntax.
(To me the syntax seems to be at the wrong level. I don't expect a block construct to affect the evaluation of expressions within the block.)
(It might be interesting to consider interactions between this and the check error handling proposal described at https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling.md . Could we use check both for error handling and for numeric overflow checks?)
Most helpful comment
This is a lot of mechanism to add for a relatively small part of the language.
cc @bcmills