Hi, I'm trying to use Nim in order to create a variable of a certain type in dependence of a certain input. I'm using the following part of code:
type Uno = object of RootObj
x: float
type Due = object of Uno
type Tre = object of Uno
y: float
proc newDue(x: float): Due {.inline.} = Due(x: x)
proc newTre(x, y: float): Tre {.inline.} = Tre(x: x, y:y)
var appo = 1.2
var caz = (if appo>1: newTre(0.5, 2.0) else: newDue(1.0))
echo caz
I don't get why, when i print caz content, it just gives the following output: (x: 0.5)
I would expect to obtain also a y value, considering that Tre type has x, y labeled data member. What am i missing? Thanks
Change the last line to echo caz.repr and you'll see why:
Uno(x: 0.5)
What other type could it have? appo is tested at runtime, and both branches of the conditional have to return the same type because the conditional itself is an expression with a single type. Although the y data is still there, it has to be retrieved with a runtime check:
echo caz.Tre.repr # Tre(y: 4.940656458412465e-324, x: 0.5)
which fails at runtime if that's invalid:
var appo = 0.5
var caz = (if appo>1: newTre(0.5, 2.0) else: newDue(1.0))
echo caz.repr # Uno(x: 1.0)
echo caz.Tre.repr # Error: unhandled exception: invalid object conversion [ObjectConversionDefect]
And how about a compile-time test of compile-time data?
const appo = 0.5
var caz = (when appo>1: newTre(0.5, 2.0) else: newDue(1.0))
echo caz.repr
echo caz.Tre.repr # Error: type mismatch: got 'Due' for 'caz' but expected 'Tre = object'
You get a compile-time error there, because caz is no longer an Uno, because the compile-time branches really can return different types. With the last line commented:
Due(x: 1.0)
This seems to work, but for some reason it shows a wrong value for y.
method `$`(x: Uno): string {.base.} =
system.`$`(x)
method `$`(x: Due): string =
system.`$`(x)
method `$`(x: Tre): string =
system.`$`(x)
Oh, you did not declare the types as ref. Polymorphism does not work with plain objects because there is no place to store the virtual tables. Try this:
type Uno = ref object of RootObj
x: float
type Due = ref object of Uno
type Tre = ref object of Uno
y: float
proc newDue(x: float): Due = Due(x: x)
proc newTre(x, y: float): Tre = Tre(x: x, y:y)
method `$`(x: Uno): string {.base.} =
system.`$`(x[])
method `$`(x: Due): string =
system.`$`(x[])
method `$`(x: Tre): string =
system.`$`(x[])
var appo = 1.2
var caz = (if appo>1: newTre(0.5, 2.0) else: newDue(1.0))
echo caz