MarkShark 27 Posted Thursday at 10:41 AM 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
Lajos Juhász 318 Posted Thursday at 10:52 AM This also fails in XE5 and 11.2. 1 Share this post Link to post
PeterBelow 253 Posted Thursday at 12:23 PM 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... 🙂 3 Share this post Link to post
MarkShark 27 Posted Thursday at 12:46 PM (edited) 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 Thursday at 01:04 PM by MarkShark Share this post Link to post
Remy Lebeau 1581 Posted Thursday at 04:06 PM 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. 2 Share this post Link to post
pmcgee 27 Posted 6 hours ago (edited) 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 6 hours ago by pmcgee Share this post Link to post
Brian Evans 122 Posted 5 hours ago 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
Uwe Raabe 2137 Posted 5 hours ago (edited) 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 5 hours ago by Uwe Raabe Share this post Link to post
Remy Lebeau 1581 Posted 1 hour ago What I described earlier is based on stepping through the actual RTL source code. Adding Variant(string) + Variant(TBcd) converts the string to a TBcd, it does not convert the TBcd to a string. Share this post Link to post