1
votes

Delphi enumeration values are natively defined as unsigned integers - 1, 2 or 4 bytes, depending on the setting of MINENUMSIZE.

I have a case where we are using Variants to transfer data of different data types between applications. All other data types work nicely, but now we realised that the expectation from other applications is that the enumerated values should be signed integers instead of unsigned (and some are really validating this).

Is there a way to configure the automatic variant conversion that the enumeration values would be converted to varInteger, instead of varUInt32?

The background: we are writing library code for OPC UA. OPC UA defines a type called Variant, which has history in Windows Variant, but is now defined in a different way. In practice, OPC UA defines that enumeration values are transferred as Int32 over the wire.

OPC UA also defines a data type called DataValue, which consists of the Value (as Variant), StatusCode (UInt32) and some Timestamp fields.

Now, we are using Delphi Variants for mapping the OPC UA Variant, since it works nicely in general. Now the only major pitfall is that when you write an enumeration value to the Variant it is converted to UInt32, whereas OPC UA expects Int32.

The library takes in Variants (in DataValues) and as an application developer, you can just assign your enumeration values to the DataValue and everything looks good. However, the value has been converted to an UInt32 and when the library code sees this Variant it cannot know anymore that it corresponds actually to an enumeration type of variable.

Should we be able to control the automatic conversion (or actually the native data type of enumerations), we could simply get rid of this problem with that.

If that is not possible, we will really have to invent conversion code, wherever we can, but which can never be 100% certain, after all.

1
Can't you simply cast the enum value to integer? Integer(uvYourThingy)GolezTrol
Well, yes, except that this is generic library code and I don't have full control over what values the developers will be writing to the variants.Jouni Aro
That comment doesn't make any real sense to me. You seem to be saying, "how can I exert control over what the variant holds, without being able to exert any control over what the variant holds?" It's like saying, "I want to let developers write arbitrary values to an integer value, but I want to make sure that those values are always positive".David Heffernan
OK, I should explain a bit more about the background to make it more sensible.Jouni Aro
So, I'd probably enforce this using developer rules. If the point where you pass the value on is too late, enforce this at the point where it is assigned. Don't use variants in your code, use your own type that encapsulates a variant type and has setter methods that can take the right decision because they know at that point they are getting an enum.David Heffernan

1 Answers

3
votes

You can't distinguish between assignment of enumerated type to variant, and assignment of integer type to variant. Consider the following code:

uses
  System.SysUtils;

type
  TFoo = (foo, bar);

var
  V: Variant;
  enum: TFoo;
  b: Byte;

begin
  V := enum;
  V := b;
end.

The compiler generates the following:

Project52946989.dpr.14: V := enum;
00422562 B8389F4200       mov eax,$00429f38
00422567 33D2             xor edx,edx
00422569 8A15489F4200     mov dl,[$00429f48]
0042256F B101             mov cl,$01
00422571 E8BED1FFFF       call @VarFromInt
Project52946989.dpr.15: V := b;
00422576 B8389F4200       mov eax,$00429f38
0042257B 33D2             xor edx,edx
0042257D 8A15499F4200     mov dl,[$00429f49]
00422583 B101             mov cl,$01
00422585 E8AAD1FFFF       call @VarFromInt

So even if you hook the library routine that handles such an assignment (System.Variants._VarFromInt), you will inevitably pick up assignments of Byte values as well as enumerated type values.

The above code assumes single byte enumerated type size, but nothing much changes for 2 or 4 byte enumerated types. Instead of the assignment looking like a byte assignment it looks like a Word or LongWord assignment, respectively.