Menu ▾ ▴

#83 Nullable types: AssignVariant handles a value it cannot convert differently in every type

AssignVariant (and FromVariant, which calls it) does something different in each nullable type when it gets a value it cannot convert. Some raise, some just become invalid, the exception classes differ, and only TNullableDate documents what it does. Measured with Delphi 12 Win32 ("invalid" means no exception and IsValid False afterwards):

Null, Empty 42 'abc' VarArrayOf([1, 2]) 1e300 NaN
TNullableDate invalid valid EConvertError EConvertError EConvertError EConvertError
TNullableDateTime invalid valid invalid invalid invalid invalid
TNullableTime invalid invalid invalid invalid invalid invalid
TNullableString invalid valid valid EVariantConvertError valid valid
TNullableInt32 invalid valid EVariantConvertError EVariantConvertError EVariantConvertError EVariantConvertError
TNullableInt64 invalid valid EVariantConvertError EVariantConvertError valid (*) valid (*)
TNullableDouble invalid valid EVariantConvertError EVariantConvertError valid valid
TNullableUInt32 invalid valid EVariantConvertError EVariantConvertError invalid invalid
TNullableUInt64 invalid valid invalid EVariantConvertError invalid invalid
TNullableGuid invalid invalid invalid EVariantConvertError invalid invalid

(*) with a wrong value; on Delphi 2007 the 1e300 and NaN cells of Int32, Int64, UInt32 and UInt64 raise EInvalidOp instead. Both come from the TryVar2Xxx functions underneath, see [bugs:#82].

So:

  • TNullableDate raises EConvertError (it is the only one with an ErrorHandling parameter), the numeric types and TNullableString raise EVariantConvertError for some values, TNullableDateTime, TNullableTime and TNullableGuid never raise for these values, and TNullableUInt64 raises for an array but not for 'abc'.
  • TNullableGuid.AssignVariant raises for an array although it is a function that returns whether the value was valid.
  • TNullableTime only accepts a string in ISO format, the form its ToVariant writes. A varDate, which is what a TIME field's Value is, becomes invalid, while TNullableDateTime and TNullableDate accept varDate and numbers.

A caller cannot write x.AssignVariant(Field.Value) without knowing which of these behaviours the type has, and nothing tells them.

Expected: one contract for all of them, documented. One option is the one TNullableDate already has: an ErrorHandling parameter, EConvertError with ehRaiseException, invalid and False with ehNoException. Changing the default of the types that never raise today would break callers that rely on that, so their default may have to stay ehNoException.

Related

Bug Reports: #82

Discussion


Log in to post a comment.