Okay, .NETters, riddle me this.
I'm preparing the next alpha of ClojureCLR 1.11. Catching up with the final commits on the JVM side, etc. Also, extending the supported platforms to include .NET 9.0 Before packaging, I run all the tests -- and I have failing tests. Five, to be exact. All on testing unchecked casting operations: unchecked-char, unchecked-byte . unchecked-int, unchecked-long. All on casting Float.MaxValue and Double.MaxValue.
Not errors on .Net 8.0, .Net 6.0, Framework 4.x. Just on .Net 9.0.
So, what changed? Best guess.
I'll pause here.
1.11 or 1.12?
Is it related to this: "In .NET 9, itβs also able to use PGO data to optimize casts."
I'm not sure if that is the cause. I'll go read up on that. I'm not sure why optimizing casts would cause a breaking change.
This perhaps? "In .NET 9.0, floating-point-to-integer conversions have been updated to have saturating behavior on x86 and x64 machines. This means that if the converted value is too small or too large for the target type, it will be set to the minimum or maximum value for that type, respectively." -- https://learn.microsoft.com/en-us/dotnet/core/compatibility/jit/9.0/fp-to-integer
Copilot suggested this scenario in tests, based on the changes in .NET 9:
// Original test code
double largeValue = Double.MaxValue;
uint result = unchecked((uint)largeValue);
Assert.AreEqual(0xFFFFFFF9, result); // This assertion will fail in .NET 9.0
// Updated test code
double largeValue = Double.MaxValue;
uint result = unchecked((uint)Math.Min(largeValue, UInt32.MaxValue));
Assert.AreEqual(UInt32.MaxValue, result); // This assertion should pass in .NET 9.0(I haven't poked at this to see whether it's even sane, so take this with an AI-sized grain of salt)
Thanks for finding that article. This does explain what I observed. In ClojureCLR, unchecked casting for integral primitives and char does a conversion to Int64 and then casts to the target type (char, byte, int, etc.).
Under .Net 8 and prior, Single.MaxValue and Double.MaxValue convert to Int64.MinValue. Under .NET 8, they convert to Int64.MaxValue.
I can't imagine too many people rely on Single.MaxValue converting to character \u0000 vs \uffff.
But if so, they'll just have to adjust. We run on .NET. We cope with what we're dealt.