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

You can read: https://documentation.xojo.com/api/data_types/variant.html#automatic-conversion-of-values

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 you instead use:

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.

image

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:

image

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)

https://tracker.xojo.com/xojoinc/xojo/-/issues/71409

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.

Screenshot 2023-01-14 at 17.18.30

1 Like