csharplang/meetings/2017/LDM-2017-05-26.md
2017-05-30 15:56:12 -07:00

3.3 KiB

C# Language Design Notes for May 26, 2017

Raw notes, yet to be cleaned up - read at your own peril

Agenda

  • Native ints

Native ints

  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 native ints and add an attribute to persist in metadata (doesn't solve ToString)
    2. project language nint etc to user defined structs
  4. A combo of 1 and 3

State of the world: We have IntPtr which has crappy arithmetics, and enough use that it would be breaking to change anything.

Xamarin need to do interop, so they have a user defined struct.

IntPtr has a few operators: + with int, which is checked on 32 bit and unchecked on 64 bit! And some conversions. Plus a very unfortunate ToString implementation.

3.2 looks like this:

struct NativeInt 
{ 
	public IntPtr Value;
	public override string ToString() { ... }
}
/// etc

But operators are implemented by the language, not as UD operators.

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

A downside is that operations that take ref IntPtr (like Interlocked...) 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 corlib. 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 - 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 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 UD 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

Objection to 3.1:

  • No runtime distinction (reflection and ToString)
  • ToString happens all the time

Who has the benefit

  • Identity conversion: 3.1
  • ToString: 3.2
  • IL efficiency: 3.1
  • Preserve the type on boxing: 3.2
  • Adoption cost: 3.1, but only slightly
  • Can overload: 3.2
  • Does not need to overload: 3.1

We're 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.