- Detailed review of https://github.com/dotnet/csharplang/blob/main/proposals/checked-user-defined-operators.md (AlekseyTs)
https://github.com/dotnet/csharplang/blob/main/proposals/checked-user-defined-operators.md
We discussed a few syntax options:
checked
afteroperator
- put
checked
beforeoperator
- use
checked
modifier
Conclusion: Stick with proposed syntax (option 1, checked
after operator
).
PS: it will be nice for implementation to gracefully handle invalid combinations, like checked +
.
We clarified why conversions cannot be implicit
and checked
.
Generally, implicit conversions should not fail, throw or be lossy. That's already the case with (most) existing conversions and .NET guidelines.
There's an exception: integer to floating point conversion in C# does allow loss.
Conclusion: Stick with proposed restriction (conversions cannot be implicit
and checked
).
The proposal is that there are regular operators
(without a keyword) and checked operators
(with checked
keyword), but there is no keyword like unchecked
to express the "no keyword" default.
In some other discussions, we have have allowed a keyword to make the default explicit, but it doesn't feel that useful here. Legacy operators don't exactly have the unchecked
meaning.
Conclusion: No explicitly unchecked
operator (whether semantically equivalent to regular operators or some other meaning).
Should there be some requirements on having both operators when a checked
operator is declared?
What combinations do we allow? 0. provide none
- provide both
- provide only regular/unchecked
- provide only checked
The only combination we could consider restricting is (3). But that seems a valid case when you don't know what to do for overflow. There's a question whether should declare a regular operator in such case.
Conclusion: No requirement. We may revise this after follow-up discussion on overload resolution rules.
There's a risk users would assume that checked
keyword affects context in method body.
But we feel users are likely to want to implement their own checks and use unchecked logic in the body, and we don't want such cases to require use of unchecked
:
operator checked ++(...)
{
unchecked { ... }
_ = unchecked(...);
}
For example, some types like uint128 need some checked and some unchecked logic in their checked operators:
result.lower = left.lower + right.lower; // overflow is expected/by-design
result.upper = left.upper + right.upper; // overflow is an exception for checked operator
We considered some possible rules for producing a warning. For example: a checked
operator must has an checked
or unchecked
block/context.
Conclusion: No warning in the language. We encourage analyzer or IDE help. Can be revised based on feedback.
Proposal API names seem straightforward but should be reviewed through API review. op_UnsignedRightShift already establishes precedent on naming schema.
We reviewed the alternatives listed in the proposal doc, and explored some variants.
It's not obvious that we should favor a checked operator on base type over an unchecked/regular operator on closer type, in a checked context.
It's not obvious whether the rules should be symmetric (checked picked first in checked context, unchecked/regular picked first in unchecked context) or asymmetric (checked operator can only be picked in checked context).
We discussed how to represent a type with only a checked operator. Should that literally be a checked
operator, or rather a regular operator?
The main alternative proposal we explored:
- lookup would find the nearest applicable candidate (
checked
operator only applicable in checked context, regular operator applicable in either context) - in checked context, if there's any
checked
candidates, discard the unchecked ones
Conclusion: proposal will be spelled out and re-discussed in LDM.