Jump to content
MarkShark

Possibly interesting issue with a variant holding a Bcd.

Recommended Posts

Hi All,

 

I was doing some work with database parameters containing a binary coded decimal and ran into an odd issue with variants.  It appears that converting a variant containing a TBcd to a string works fine, but converting and concatenating to another string does not.  Any thoughts?  Thanks!  (I'm using Delphi 12.3 (with the latest patch) but have not tested on earlier versions to see if it's version specific.)

 

procedure TForm1.Button1Click(Sender: TObject);

// Example of issue.  Uses System.Variants and Data.FMTBcd
var
  V: Variant;
  S: String;
  Bcd: TBcd;
begin
  Bcd := IntegerToBcd(23);
  VarFMTBcdCreate(V, Bcd);
  // This assignment works.
  S := V;
  // This concatenation fails (Delphi 12.3)
  // Project VarTestVcl.exe raised exception class EBcdException with message
  // 'Testing:  is not a valid BCD value'.
  S := 'Testing: ' + V;
end;

Easy to work around, but seemed an odd issue!

Share this post


Link to post
1 hour ago, MarkShark said:

S := 'Testing: ' + V;

The error message indicates that the compiler is not evaluating the right-hand side expression as you expect. Instead of converting V to a string and concatenating the result to the string literal it is trying to convert the literal to a variant containing a TBcd, adding the two numbers, and then convert the result to a string. If you have a masochistic streak put a breakpoint on the statement, run to it, call up the disassembly view and F7 through the generated code (debug dcus need to be enabled).

 

I would not call that a bug, just unexpected behaviour. But as you know, in programming the compiler is always right... 🙂

  • Like 3

Share this post


Link to post

Peter you are 100% correct!   S := '1' + V;  works and returns 24 (both if V has a bcd, or if it just contains an integer.)  It looks like this is just my own misinterpretation of how concatenating variants works.  I always thought the conversion took into account the type of the first "item" in the concatenation.  And agreed on the bug thing, I always go with "Issue" until someone else confirms things (or I learn something new, which is always appreciated!)

Edited by MarkShark

Share this post


Link to post
3 hours ago, MarkShark said:

It looks like this is just my own misinterpretation of how concatenating variants works.  I always thought the conversion took into account the type of the first "item" in the concatenation.

It does, but in this case, since the operation involves a native type (string) on the left and a custom user type (TBcd) on the right, the operation gives the custom type an opportunity to decide whether to cast the left side to the custom type, which it does in this situation, and then the failure occurs during that cast from string to TBcd.

  • Like 2

Share this post


Link to post

There is a section of the programming community, from eg Alexander Stepanov, to eg Jason Turner (of C++Weekly)
 

That consider implicit conversion to be evil, or a safety issue. (https://news.ycombinator.com/item?id=24806884)

(Google shows me links about it from 2005, 2010, 2015, and 2020 🙂 )

I guess their argument is for explicit casts (if absolutely necessary), over what might be termed 'a wing and a prayer'. 

 

Certainly this works :  

S := 'Testing: ' + string(V);

 

Edited by pmcgee

Share this post


Link to post
On 5/8/2025 at 12:06 PM, Remy Lebeau said:

It does, but in this case, since the operation involves a native type (string) on the left and a custom user type (TBcd) on the right, the operation gives the custom type an opportunity to decide whether to cast the left side to the custom type, which it does in this situation, and then the failure occurs during that cast from string to TBcd.

My understanding is for expressions with variants non-variants are converted to a variant and operations like + follow Windows OLE (varAdd) in how they are combined. Neither cares about the order of variants/types just about combinations.

 

string + variant with BCD value becomes variant with string value + variant with BCD value. For adding variants string+number or number+string both add numbers.

 

 

Ref: https://docwiki.embarcadero.com/RADStudio/Athens/en/Variant_Types_(Delphi)#Variants_in_Expressions

Quote

If an expression combines variants with statically-typed values, the statically-typed values are automatically converted to variants.

Ref: https://learn.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-varadd#remarks

Quote
Condition Result
Both expressions are strings Concatenated
One expression is a string and the other a character Addition
One expression is numeric and the other a string Addition
Both expressions are numeric Addition
Either expression is null Null
Both expressions are empty Integer
   
   
   
   
   
   

Share this post


Link to post
15 minutes ago, Brian Evans said:

My understanding is for expressions with variants non-variants are converted to a variant

That is even mentioned in the docs (https://docwiki.embarcadero.com/RADStudio/Athens/en/Variant_Types_(Delphi)#Variants_in_Expressions

Quote

If an expression combines variants with statically-typed values, the statically-typed values are automatically converted to variants.

 

Edited by Uwe Raabe

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×