Am I misunderstanding this method?

I have this C# code snippet:

ulong codePoint = Convert.TryHexStringToUInt64(hexString);
if (codePoint == null) {
  // Invalid code point.
  Error("Invalid Unicode codepoint `" + hexString + "`.");
} else {
  lex += codePoint.ToUTF16String();
}

The compiler is warning me that if (codePoint == null) { will always be False. Why is this? I thought that if I passed TryHexStringToUInt64() an invalid codepoint it would return null?

because code point is defined as a ulong which, is a value type and =thus never nil.

now, yes, Convert.TryHexStringToUInt64 returns a nullable ulong (aka UInt64), true, but hardcoding a type in the bvafriable declaration will override type inference. iff you were to write

ulong? codePoint = Convert.TryHexStringToUInt64(hexString);

or (better)

var codePoint = Convert.TryHexStringToUInt64(hexString);

then this code would work as you expect. but as written, you “force” the result into a non-nullable UInt64, and as a consequence, the following if statement will always be false.

hmm.

Changing ulong codePoint = Convert.TryHexStringToUInt64(hexString); to ulong? codePoint = Convert.TryHexStringToUInt64(hexString); fixes the warning but breaks the line lex += codePoint.ToUTF16String() saying there is “no such member” for ToUTF16String().

Changing ulong codePoint = Convert.TryHexStringToUInt64(hexString); to var codePoint = Convert.TryHexStringToUInt64(hexString); fixes the warning but agin breaks the line lex += codePoint.ToUTF16String() saying there is “no such member” for ToUTF16String().

If I use var and try to cast code point to a ulong (since I know it will be) then I still get the “no such member” error for codePoint.ToUTF16String ():

var codePoint = Convert.TryHexStringToUInt64(hexString);
if (codePoint == null) {
  // Invalid code point.
  Error("Invalid Unicode codepoint `" + hexString + "`.");
} else {
  lex += (ulong)codePoint.ToUTF16String(); // <-- no such member
}

Hmm. what platform is this? unfortunately there’s some inconsistency with how nullables auto-unwrap (or don’t) in C#, for compatibility with VC# — but that should only affect .NET.

two options, either you need to call .value (eg codePoint.value.ToUTF16String, or change your if clause around like this:

if (codePoint != null) {
  lex += (ulong)codePoint.ToUTF16String(); // inside the IF, its unwrapped.
} else {
  // Invalid code point.
  Error("Invalid Unicode codepoint `" + hexString + "`.");
}

This has been an area of frustration for me too, and I’m going back and forth within he compiler team on addressing this, for consistency over VC# compatibility…

Yep that fixes it @mh, thanks. This is coding on macOS with Fire, testing on Island (a console application).

Does that imply that unwrapping doesn’t happen in the else clause? Seems odd.

Curious,. maybe Island behaves same as .NET then. I’ll get this reviewed/reconsidered again, as promised.

it’s a special case that after “if x != null” and "if assigned(x)', a nullable x will be considered known non-null. Think of it was the equivalent if if let x = in Swift.

1 Like