64 lines
3.4 KiB
Markdown
64 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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|