Variant Currency Bug?

Am I missing something here? Seems to be a bug. Someone let me know if you agree and I will report it

``````var c as Currency = 6.77

var v as Variant = c

var i as integer = v * 1000

'i should be 6770. Is it?
break 'NO

i = c * 1000

'now is it 6770?
break  'YES! Bug why now and not before?
``````

I have read a couple of times that with Variants the compiler needs to guess (or something to that effect) as how to handle the value there.

It looks like, in this case, the variant is defined as integer when it is assigned to the integer before doing the calculation and/or because 1000 could be integer.

If you change

``````var i as integer = v * 1000
``````

to

``````var i as integer = v * 1000.0
``````

then i = 6770 on the first break.

Clearly a horrendous bug.

``````var c as Currency = 6.77

var v as Variant = c

var d as double = v * 1000

break // 6000 ? Why did it discard the decimals?
``````

Is it linked to the fact of my Windows locale using comma as decimal and under the hood Xojo does some mess? If something canâ€™t happen in a compiler is bad math.

The expression evaluator is messed.

Xojo 2022r4.1 fell from degree 7.6 to 4.2 now.

Who will report? @Brandon_Warlick

Things are worse:

``````var v as Variant = 6.77

var d as double = v * 1000

break // 6000 ? Unacceptable!
``````

Not currency related, itâ€™s an expression evaluator bug, maybe aggravated by variants in the expression

If there is any ambiguity concerning the type conversion of a Variant, you should use one of the properties of the Variant class to force the compiler to convert the Variant to the desired type

Consider the following example:

``````Var v As Variant = 0.5
``````

The comparison:

``````If v > 0 Then
``````

returns False since v is being treated as an Integer and will round down to 0.

``````If v > 0.0 Then
``````

the comparison returns True.

2 Likes

Why in any world a variant in such context would be treated as integer? What other language presents such aberration? VB6 does it? VB.Net? If they do it I can drop the case.

Yes. As AlbertoD mentioned, you are asking the compiler to guess what type you want to cast the variant to.

You can give it a hint using a double value instead of an integer like this:

``````var i as integer = v * 1000.0
``````

But it is still guessing. The correct way to use variants in xojo, as documented is to â€śuse the properties of the Variant class to force the compiler to convert the variant to the desired type.â€ť:

``````Var i As Integer = v.DoubleValue * 1000
``````

So, NOT a bug, just the (controversial) default behavior of the languaje.

Using Ivanâ€™s terms, the compiler is not guessing, its using a dumb rule. And destroying the content of a variable in a way not encountered in ANY other language that I know. So when you are alone doing something as dangerous as it is doing, you are the wrong guy.

This behavior, even documented, is unacceptable. If it needs to default to some dumb numeric type, it should be double to preserve 99% of the values. No programmer of any other language will expect such behavior. It needs reevaluation.

Or use

``````Var i As Integer = v.CurrencyValue * 1000
``````

Variants in Xojo are pretty squirrely. You have to take care and be very explicit with them. Personally, I would write it as

``````var c as Currency = 6.77
var v as Variant = c
...
var c2 as Currency = v
var i as integer = c2 * 1000
``````

Knowing that you got v from somewhere else.

Thank you to show another behavior aberration. No ONE would expect such unusual behavior easily fixed in the current broken expression evaluator.

When any part of the expression contains a variant, the compiler should switch to an expression evaluator with runtime type resolution. Itâ€™s a bit slower than a static one, but always will end with correct value.

So, for something like

``````Var r As Boolean
Var v As Variant = 0.5
r =  v > 0 // MUST BE True or the evaluator is broken
``````

Xojo currently sees something like this at compile time,

Boolean = ? > Integer

And lazy and wrongly it â€śsolves itâ€ť statically at compile time:

Boolean = Integer(Variant) > Integer
â†’ r = Boolean(Integer(v) > 0)

Destroying the v value and ending with a wrong result.
You can only solve statically nodes with defined and known types at compile time, otherwise, runtime type resolution must be used during the evaluation to get the correct results.

This case should be:

Boolean = Variant(Double) > Integer // That double is enveloped at runtime and unknown at compile time

Once an expression contains a variant, it should evaluate it at runtime consulting the current types of both sides of the current expression node (x operator y) or sometimes just one and matching a static one as below

``````Boolean = Boolean(GreaterThan(Variant, Integer)) // This function unpacks the variant to the real value and performs the correct comparison or throws an error if invalid using whatever correct value it contains and returns 0 or 1 casting it back to Boolean for assignment
r = v > 0
--> r = _VariantGreaterThan(v, 0) // Yes, this will end as 0.5 > 0? -> True
``````

Howâ€™s the correct behavior? This way:

What Xojo does? The unimaginable.

``````Var r1, r2 As Boolean

Var v As Variant = 0.5
Var d As Double = 0.5

r1 = v > 0 // MUST BE True, if False, the expression evaluator is broken, and it is
r2 = d > 0 // Same thing, just static, not enveloped at runtime

If not(r1 and r2) Then // Both logically MUST BE true
MessageBox "The expression evaluator is broken"
break
Else
MessageBox "The expression evaluator is OK"
End

Quit
``````

If no one fix this bug, We need a compiler switch to declare as error any place containing any math/bitwise/boolean expression with a variant. This will enforce fixing program parts subject to silent errors, forcing the dev to replace such variant with a static one as Double, Currency, Integerâ€¦

1 Like

This could be done in 2 steps:

1. A compiler switch to consider variant expressions as errors, and continue with the current wrong evaluator. Something as â€śError: Donâ€™t use Variants in expressions. Convert such values to static types.â€ť

2. A new evaluator is created fixing the current bugs. Once released, the Error switch for variant expressions can be demoted to a Warning as â€śWarning: Thereâ€™s an expression with a variant type here. Be sure itâ€™s correct.â€ť an the build continues anyway.

No problem, it is part of the documentation and has been for many years.

This is how Variants were designed by Xojo. As Ivan said:

As the documentation says:

If there is any ambiguity concerning the type conversion of a Variant, you should use one of the properties of the Variant class to force the compiler to convert the Variant to the desired type

and

Variants used in an expression convert themselves to the type of the other operand

You can open a Feature Request to change this behavior if you want, as a Bug report will be closed with â€śAs Designedâ€ť.

This canâ€™t be â€śby designâ€ť. No one designs something able to make 6.77 * 1000 = 6000. It is just the result of â€śwe have lots of other bugs to fix and a proper evaluator will cost time, so letâ€™s just document it and let apps explode around the world until they find the problemâ€ť.

Thatâ€™s clearly a bug, as proven. And as said, users can avoid that trap with little cost for Xojo with them just introducing a compiler switch raising a compiler error when finding such possibility while it canâ€™t do it correctly using some type of RTTI technique.

1 Like

No matter what you say will change the fact that the behavior is documented so they will not change how variants work.

You are seeing V as 6.77 but Xojo sees it as 6 because the other operand is an integer.

I guess if someone writes this code:

``````Var v As Variant = "6.77"
Var i As Integer = v * 1000.
``````

you want Xojo to throw an error because V is a string and should not be changed to double, right? (v is used as double because I put a period after 1000)

Documented or not. Being the UNIQUE language in the world able to create such class of silent horrible known math errors should suffice to make them look at the bugs.

The rest of your argumentsâ€¦ What I do expect? Let me seeâ€¦ This:

But if I canâ€™t get it, I want the compiler impeding me of trying.

Do you have a case number yet?

Brandon did not say one yet. Maybe I will report one if none arises.

Iâ€™ve been thinking about it and it can be debated whether or not this is a bug. I think it is a bug because it is not consistent among datatypes. Fixing may cause issues in existing code but I canâ€™t imagine someone getting upset that their Currency calculations were incorrect and now they are fixed.

Here is a summary:
If you assign a currency to a variant and then calculate something with the variant, the result is incorrect. However, if you do the same thing with an integer or string, the result is correct. Currency variants should work the same way.

``````var v as variant

'This works as expected with String
var sInitialValue as String = "ABC"
v = sInitialValue

If VarType(v)=Variant.TypeString then
var s as string = v + "DEF"
break 's="ABCDEF"
end if

'This works as expected with Integer
var iIntialValue as Integer = 1
v=iIntialValue

If VarType(v)=Variant.TypeInt64 or VarType(v)=Variant.TypeInt32 then
var i as integer = v + 2
break 'i=3
end if

**'This DOESN'T work as expected with Currency**
var cInitialValue as Currency = 1.56
v = cInitialValue

If VarType(v)=Variant.TypeCurrency then
var c as currency = v * 100
break 'c=100
end if

'Yes, you can make it work by explicitly asking for CurrencyValue
If VarType(v)=Variant.TypeCurrency then
var c as currency =  v.CurrencyValue * 100
break 'c=156
end if

'While I'm complaining about variants, Variant.TypeInteger should be removed from autocomplete
v = iIntialValue
var b as Boolean

If VarType(v)=Variant.TypeInteger then
b=True
else
b=False
end if
break  'b=false, (yeah i know, it is either an int32 or int64 so you have to check for both for 32bit or 64bit apps)

``````

1000 is an integer constant, 1000.0 is a double constant. Your use of Variant * Integer is causing the integerisation. If you say Variant * 1000.0 it would come out as you expect. Look at the constants they are coloured differently in Xojo.

1 Like