# .net is a extremly dangerous thing ;-)

• Karl-Heinz Rauscher
• Topic Author
• Offline
4 months 2 weeks ago #1 by Karl-Heinz Rauscher
.net is a extremly dangerous thing ;-) was created by Karl-Heinz Rauscher
```FUNCTION DoConsole2() AS VOID
LOCAL fTotal AS double

Console.WriteLine("{0,12:###,##0.00}" + "{1,12:###,##0.00}" + "{2,20:###,###,##0.00}" , aDouble)
fTotal += (double) aDouble [ 3 ]

aDouble [ 1 ] := -1223.56
aDouble [ 2 ] := 7869

Console.WriteLine("{0,12:###,##0.00}" + "{1,12:###,##0.00}" + "{2,20:###,###,##0.00}" , aDouble)
fTotal += (double) aDouble [ 3 ]

// 12 + 12 == 24
Console.WriteLine(space ( 24 ) + repl ( "-" , 20 ) )
// 12 + 12 + 20 == 44
Console.WriteLine("{0,44:###,###,##0.00}" , fTotal )

RETURN
```

find the (runtime) problem

regards
Karl-Heinz

4 months 2 weeks ago - 4 months 2 weeks ago #2 by Wolfgang Riedmann
Replied by Wolfgang Riedmann on topic .net is a extremly dangerous thing ;-)
Hi Karl-Heinz,

I had similar problems with conversions....

It is very bad that .NET does not handles this and that you have to specify
```aDouble [ 1 ] := -1223.56d
aDouble [ 2 ] := 7869d```

Wolfgang
Last edit: 4 months 2 weeks ago by Wolfgang Riedmann. Reason: Correction of code

4 months 2 weeks ago #3 by Wolfgang Riedmann
Replied by Wolfgang Riedmann on topic .net is a extremly dangerous thing ;-)
Hi Karl-Heinz,

```aDouble [ 1 ] := ( double ) -1223.56
aDouble [ 2 ] := ( double ) 7869```

In our VO understanding a numeric is a numeric and there is no runtime error when they are converted for and back.
It is really a pity that a numeric calculation between an int32 and a double fails at runtime!

Wolfgang

4 months 2 weeks ago #4 by Chris Pyrgas
Replied by Chris Pyrgas on topic .net is a extremly dangerous thing ;-)
Guys,

.Net actually does handle it well, but we must be careful with what we are doing. The code (simplified to make it easier to follow):
`aDouble [ 3 ] := (double) aDouble [ 2 ]`

Does a type cast from object to double, so we tell the compiler that we know that aDouble [ 2 ] holds a double, which apparently in this case is not true. What we really should be doing, is to use a conversion, not a cast, as in:
`aDouble [ 3 ] := Convert.ToDouble( aDouble [ 2 ] )`

This will always work correctly, provided that the type of aDouble [ 2 ] can be converted to a double.

Of course he "Convert" method is slower, but it is safer to use in such code.

Chris

XSharp Development Team
chris(at)xsharp.eu

4 months 2 weeks ago #5 by Chris Pyrgas
Replied by Chris Pyrgas on topic .net is a extremly dangerous thing ;-)
Hi Wolfgang,

wriedmann wrote: Hi Karl-Heinz,

```aDouble [ 1 ] := ( double ) -1223.56
aDouble [ 2 ] := ( double ) 7869```

In our VO understanding a numeric is a numeric and there is no runtime error when they are converted for and back.
It is really a pity that a numeric calculation between an int32 and a double fails at runtime!

Wolfgang

To be precise, it is not the calculation that fails, but the cast, which is indeed incorrect. You can do calculations between Int32 and Double just fine:
```LOCAL r AS REAL8
LOCAL n AS INT
r := n + r```

as long as the target var type is "larger" (or same) than the operands.

But when you are doing calculations between objects that the runtime knows nothing about at compile time (calculation between System.Object types), then you need to convert them to the data type you want first.

Chris

XSharp Development Team
chris(at)xsharp.eu

4 months 2 weeks ago - 4 months 2 weeks ago #6 by Jamal
Replied by Jamal on topic .net is a extremly dangerous thing ;-)
Not sure this is a .NET thing, but more of a language specific.

I used C# and VB.NET.
C# is very strict on casting, however, VB.NET handles double correctly.

Jamal
Last edit: 4 months 2 weeks ago by Jamal.

4 months 2 weeks ago #7 by Wolfgang Riedmann
Replied by Wolfgang Riedmann on topic .net is a extremly dangerous thing ;-)
Hi Chris,

thank you very much for your explanations!

Theoretically also the cast from an int32 to a double should work....

Wolfgang

4 months 2 weeks ago - 4 months 2 weeks ago #8 by Chris Pyrgas
Replied by Chris Pyrgas on topic .net is a extremly dangerous thing ;-)
Hi Wolfgang,

wriedmann wrote: Hi Chris,

thank you very much for your explanations!

Theoretically also the cast from an int32 to a double should work....

Wolfgang

They are different data types, with different internal representation, and just because they are both numeric types, does not mean they can be cast one to another (of course conversion is a different thing). It's like expecting to be allowed to do (System.Collections.SortedList)oMyDisctionary, because both SortedList and Dictionary are both collection types.

Try doing the equivalent of casting in VO:
```LOCAL n AS INT
LOCAL r AS REAL8
r := 1.2
n := INT(_CAST,r)
? n```

this will not throw an exception/error in VO, but the result will not make sense either.

Note that in this particular case, in .Net such a (memory mapped) cast is not allowed, so if you compile this with X# (or vulcan), the compiler will actually create code that makes a conversion! It does that, because it knows at compile time exactly the data types involved (INT and REAL8) and can safely convert from one to another, while it cannot do that for vars declared as Object.

Edit: So, to summarize, my suggestion is when every time when dealing with objects that are non known at compile time, always use the Convert methods to be safe. Unless you want to use USAULs of course, which take care of this at runtime!

Chris

XSharp Development Team
chris(at)xsharp.eu
Last edit: 4 months 2 weeks ago by Chris Pyrgas.

• Karl-Heinz Rauscher
• Topic Author
• Offline
4 months 2 weeks ago #9 by Karl-Heinz Rauscher
Replied by Karl-Heinz Rauscher on topic .net is a extremly dangerous thing ;-)
Guys,

c# throws the same runtime error. The "problem" is that an array of "simple" Objects must be used to feed the Console.WriteLine(), instead of the possibility to use an typed array of e.g. doubles. The lesson learned in conjunction with "simple" Objects: Don´t trust your human senses, especially if you have VO roots

// something like this gives no such problems.

VAR fDouble := <DOUBLE>{2.50, 3 , 12.45 }

fDouble [ 1 ] := 1234
fDouble [ 2 ] := -12
fDouble [ 3 ] := fDOuble [ 1 ] + fDouble [ 2 ]

? fDouble [ 1 ]
? fDOuble [ 2 ]
? fDouble [ 3 ]

regards
Karl-Heinz

• Karl-Heinz Rauscher
• Topic Author
• Offline
4 months 2 weeks ago #10 by Karl-Heinz Rauscher
Replied by Karl-Heinz Rauscher on topic .net is a extremly dangerous thing ;-)
Hi Chris,

Chris wrote:
Edit: So, to summarize, my suggestion is when every time when dealing with objects that are non known at compile time, always use the Convert methods to be safe. Unless you want to use USAULs of course, which take care of this at runtime!

Chris

So this isn´t save enough ?

aDouble [ 1 ] := (double) -1223.56
aDouble [ 2 ] := (double) 7869

regards
Karl-Heinz

4 months 2 weeks ago #11 by Chris Pyrgas
Replied by Chris Pyrgas on topic .net is a extremly dangerous thing ;-)
Hi Karl-Heinz,

Karl-Heinz wrote: So this isn´t save enough ?

```aDouble [ 1 ] := (double) -1223.56
aDouble [ 2 ] := (double) 7869

If aDouble is a an array of Double (and not array of Object), then it is absolutely safe, everything is known at compile time. But this wouldn't be safe, as the type of the oNumeric var is not known at compile time:
```LOCAL oNumeric AS OBJECT
o := 1234
aDouble [ 1 ] := (double) oNumeric```

In this case, the compiler cannot make any conversion, as it does not know from what type to convert to a Double. So it assumes oNumeric really holds a double, which fails at runtime because it actually holds an INT.

Btw, a note to everybody, this is not a compatibility problem with VO at all, because in VO you could not put numeric values into an OBJECT var...

Chris

XSharp Development Team
chris(at)xsharp.eu

• Karl-Heinz Rauscher
• Topic Author
• Offline
4 months 2 weeks ago #12 by Karl-Heinz Rauscher
Replied by Karl-Heinz Rauscher on topic .net is a extremly dangerous thing ;-)
Hi Chris,

```LOCAL oNumeric AS OBJECT
o := 1234
aDouble [ 1 ] := (double) oNumeric```

In this case, the compiler cannot make any conversion, as it does not know from what type to convert to a Double. So it assumes oNumeric really holds a double, which fails at runtime because it actually holds an INT.

ok, i got it. i enhanced my sample with a second array:

VAR aDouble2 := <OBJECT>{ -23 , 276.45}

the first Element holds an int, while the second element holds a float, Without to convert aDouble2[1] to a float the program crashes.

```FUNCTION DoConsole2() AS VOID
LOCAL fTotal AS double

Console.WriteLine("{0,12:###,##0.00}" + "{1,12:###,##0.00}" + "{2,20:###,###,##0.00}" , aDouble)
fTotal += (double) aDouble [ 3 ]

aDouble [ 1 ] := (double)  -1223.56
aDouble [ 2 ] := (double) 122

Console.WriteLine("{0,12:###,##0.00}" + "{1,12:###,##0.00}" + "{2,20:###,###,##0.00}" , aDouble)
fTotal += (double) aDouble [ 3 ]

// aDouble [ 1 ] :=  (double) aDouble2 [ 1 ]  // this fails at runtime because aDouble2[1] holds an none float -> -23
// aDouble [ 2 ] :=  (double) aDouble2 [ 2 ]  // this would work, because aDouble2[2] already holds a float -> 276.45

aDouble [ 1 ] := Convert.ToDouble  ( aDouble2 [ 1 ]  )
aDouble [ 2 ] := Convert.ToDouble  ( aDouble2 [ 2 ]  )

Console.WriteLine("{0,12:###,##0.00}" + "{1,12:###,##0.00}" + "{2,20:###,###,##0.00}" , aDouble)
fTotal += (double) aDouble [ 3 ]

// 12 + 12 == 24
Console.WriteLine(space ( 24 ) + repl ( "-" , 20 ) )
// 12 + 12 + 20 == 44

Console.WriteLine("{0,44:###,###,##0.00}" , fTotal )

RETURN
```

regards
Karl-Heinz

4 months 2 weeks ago - 4 months 2 weeks ago #13 by Karl Faller
Replied by Karl Faller on topic .net is a extremly dangerous thing ;-)
Karl-Heinz,
with this:
VAR aDouble2 := <OBJECT>{ -23 , 276.45}
i think, you FORCE the compiler to treat the numbers as OBJECT, i.e. you "forbid" it to be "clever" and deduct the type.

Karl
Last edit: 4 months 2 weeks ago by Karl Faller. Reason: typo

4 months 2 weeks ago #14 by Wolfgang Riedmann
Replied by Wolfgang Riedmann on topic .net is a extremly dangerous thing ;-)
Hi Karl-Heinz,

IMHO the misunderstanding is here:
in VO we use
`float( _cast, uValue )`
to cast, and
`float( uValue )`
to convert.

In .NET,
`(double) oObject`
is a cast, and not a conversion, and since we don't work on pointers anymore, the code crashes.

Wolfgang

• Karl-Heinz Rauscher
• Topic Author
• Offline
4 months 2 weeks ago #15 by Karl-Heinz Rauscher
Replied by Karl-Heinz Rauscher on topic .net is a extremly dangerous thing ;-)
Hi Karl,

FFF wrote: Karl-Heinz,
with this:
VAR aDouble2 := <OBJECT>{ -23 , 276.45}
i think, you FORCE the compiler to treat the numbers as OBJECT, i.e. you "forbid" it to be "clever" and deduct the type.

Yes, that´s what i wanted

[...]

VAR aDouble2 := <OBJECT>{ -23 , 276.45}

the first Element holds an int, while the second element holds a float, Without to convert aDouble2[1] to a float the program crashes.

[...]

To round things off, i added another array, a <double> array,

```FUNCTION DoConsole2() AS VOID
LOCAL fTotal AS double

Console.WriteLine("{0,12:###,##0.00}" + "{1,12:###,##0.00}" + "{2,20:###,###,##0.00}" , aDouble)
fTotal += (double) aDouble [ 3 ]

aDouble [ 1 ] := (double)  -1223.56
aDouble [ 2 ] := (double) 122

Console.WriteLine("{0,12:###,##0.00}" + "{1,12:###,##0.00}" + "{2,20:###,###,##0.00}" , aDouble)
fTotal += (double) aDouble [ 3 ]

// aDouble [ 1 ] :=  (double) aDouble2 [ 1 ]  // this fails because aDouble2[1] holds an none float -> -23
// aDouble [ 2 ] :=  (double) aDouble2 [ 2 ]  // this would work, because aDouble2[1] holds already a float -> 276.45

aDouble [ 1 ] := Convert.ToDouble  ( aDouble2 [ 1 ]  )
aDouble [ 2 ] := Convert.ToDouble  ( aDouble2 [ 2 ]  )

Console.WriteLine("{0,12:###,##0.00}" + "{1,12:###,##0.00}" + "{2,20:###,###,##0.00}" , aDouble)
fTotal += (double) aDouble [ 3 ]

aDouble [ 1 ] := aDouble3 [ 1 ]  // <DOUBLE> array - no cast or convert necessary  > 123
aDouble [ 2 ] := aDouble3 [ 2 ]  // <DOUBLE> array - no cast or convert necessary  > -1276.45

Console.WriteLine("{0,12:###,##0.00}" + "{1,12:###,##0.00}" + "{2,20:###,###,##0.00}" , aDouble)
fTotal += (double) aDouble [ 3 ]

// 12 + 12 == 24
Console.WriteLine(space ( 24 ) + repl ( "-" , 20 ) )
// 12 + 12 + 20 == 44
Console.WriteLine("{0,44:###,###,##0.00}" , fTotal )

RETURN
```

regards
Karl-Heinz