csharplang/meetings/2017/LDM-2017-05-26.md
2017-06-19 17:05:19 -07:00

65 lines
3.4 KiB
Markdown

# C# Language Design Notes for May 26, 2017
## Agenda
1. Native ints
# Native ints
We would like to supply high-quality native-size integers. The best we have today is `IntPtr`, which lacks most operators and have a few behavioral weaknesses, including a suboptimal `ToString` implementation. Xamarin has introduced user-defined `nint` and `nuint` types for interop, but those can't completely do the trick; for instance, user-defined operators cannot distinguish between checked and unchecked contexts.
Options:
1. Improve `IntPtr` with operators
2. Add `nint` and `nuint` as a user defined struct (the Xamarin approach)
3. Add `nint` and `nuint` to the language
1. compile down to `IntPtr` and add an attribute to persist the additional type info in metadata
2. project language-level types to new user defined structs
4. A combo of 1 and 3
`IntPtr` has a few operators today; for instance `+` with `int` (which is checked on 32 bit and unchecked on 64 bit!), and some conversions.
The new structs in 3.2 look something like this:
``` c#
struct NativeInt
{
public IntPtr Value;
public override string ToString() { ... }
}
/// etc
```
But operators are implemented by the language, not as user-defined operators.
The difference between 3.1 and 3.2 is that with 3.2 at runtime we have different types, so we can have differentiated runtime behavior: `ToString` and reflection can tell them apart.
A downside is that operations that take `ref IntPtr` (like `Interlocked.CompareExchange`) wouldn't automatically take `ref nint`. Having the public mutable field would let things still work for people, and we could go through and add `nint` overloads over time to make it better.
This should be in mscorlib, but that takes time. Is there anything we can do to mitigate in the meantime? We could ship a nuget package etc, but there's some cost to that, including indefinite maintenance. But some of the people who would benefit from this will be in a terrible spot if we don't provide something.
We also need to deal with native float. There is no option to do 3.1 for floats; there is no `IntPtr` equivalent. So that one would need a framework type. However, we could probably live with that `nfloat` struct moving into the frameworks over time - other than Xamarin, which would add it faster for its interop scenarios.
With 3.1, if you consume a `nint`-attributed `IntPtr` with an old compiler, would it treat it as an `intPtr`? If that's the case then the code would subtly change behavior on compiler upgrade. Unfortunate! We could perhaps poison `nint` with `ModReq` so that they cannot be consumed by existing compilers, but now `nint` really *is* a different type, and requires separate overloads of methods that take it as a parameter.
Another option is to obsolete the user-defined operators on `IntPtr`, to drive people to use `nint` instead.
## Objections to 3.2:
- Adoption, where a separate struct would take a while to propagate (we feel we've mostly mitigated this)
- We'll emit slightly less efficient and more verbose IL in a couple of cases
- Needing new overloads for `nint` where there are `IntPtr` overloads today (or at least a conversion, and new overloads where there are `ref IntPtr` parameters).
Objection to 3.1:
- No runtime distinction (reflection and `ToString`)
- `ToString` happens all the time
## Conclusion
We're torn, and evenly balanced on preferring 3.1 vs 3.2. Could maybe be convinced to 3.2 if we can solve how do existing users of `IntPtr` migrate.