Xamarin’s Rough Transition to 64-bit iOS/OSX
When Xamarin started their iOS project the devices were only available in a 32-bit mode, which meant 32-bit versions of NSInteger and CGFloat. When they started looking into 64-bit OSX they realized that their assumptions about those data types was wrong. Miguel continues,
We would need to audit all of our APIs to do the proper type mapping and we would break source code compatibility, with code like this:
var foo = new Xxx ();
int count = foo.GetRowCount ();
// oops, can not cast a long into an int.
When we combined source code breakage with the fact that Apple had a 32-bit compatibility story and we had some legacy libraries that depended on 32-bit only APIs meant that we were in no rush to move to a 64-bit world.
With the introduction of 64-bit only libraries in Mountain Lion they saw a need to change this design. It was further compounded by Apple’s decision to offer 32-bit and 64-bit versions of the iPhone 5. To deal with these new challenges Xamarin has created three new data types:
These new structs are defined as 32-bit or 64-bit depending on which platform the code is being compiled to. But there is more to the story than that. Primitive math uses special IL instructions for operations such as addition while user defined structs need to call the op_Addition method.
This can cause a small but noticeable impact in performance sensitive code. Since these types are so fundamental to working with native libraries, the AOT compiler was modified to reinterpret operations with these typee. Miguel continues,
The call op_Addition ends up being the same as the native ECMA CIL add instructions. The IL might look scarier, but the native code is identical.
Some may wonder why Xamarin didn’t just go with IntPtr, the CLR data type that supports platform-specific integers. Miguel writes,
We chose the names nint, nuint over the built-in IntPtr and UIntPtr, because they felt natural "native integers" as opposed to the cultural association that IntPtr has with pointer or a native token. Additionally, we did not have the equivalent native floating point type.
We chose to stay away from using the names NSInteger and CGFloat for a couple of reasons: the functionality is general enough that it might be worth using in Mono in places beyond Mac and iOS and because it feels like these are real VM supported types as opposed to some type definition or alias. In an ideal world, these would eventually be part of the C# standard.