# 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.