Hi!
I stumbled upon nimrod while searching for examples involving perlin noise and found this little benchmark ( https://github.com/nsf/pnoise ) which shows how fast nimrod can be (only surpassed by gcc and rust here). So i dived into nimrod and i think it looks really awesome.
However i'm having some difficulty getting the right/most efficient "nimrodic way" into my head. I'm now playing with it for a day of 4 and i get the feeling a lot is possible but beyond basic stuff mentioned in the tutorial, not including macros/typeclasses at which point the learning curve makes a significant jump, I hit some sort of wall getting things done, fighting the compiler every 10'th line or so.
Which is of course a clear sign i'm looking at things the wrong way.
At this point i'm building a tree of objects that differ in type only in "kind" and their type of value field. It felt a bit overkill to use inheritance for this (as the tutorial suggests), but i want to access this value field in the same way throughout the program (and in the real program this list of kinds is much larger, so using a case-of block every time looks awkward). So the problem here is assigning/returning a value of which the type is only known at runtime.
I know i'm possibly trying to make nimrod behave more dynamic than it probably is, but then again nimrod has an auto type, gives me templates, "cast" and references, so i guess it can be done.
Googling the forum resulted in being directed multiple times to typeclasses, but as someone without formal education in type theory, its a bit beyond ready knowledge for me - and they seem to be more concerned with contracts & type safety anyway (correct me if i'm wrong)
So if someone could point me in the right direction with the following questions i would be very grateful :)
Is it somehow possible to create an array of typeDesc?
var ary : array[0..2, typeDesc] = [int32, string, float]
This doesn't work, but the error isn't very enlightening either: internal error: GetUniqueType
Leaving out the last float in the array constructor is obviously wrong but tells me:
type mismatch: got (Array constructor[0..1, typedesc]) but expected 'array[0..2, typedesc]
So why does it choke on an array of typedesc's of the right length?
With the following setup, trying to get ival/sval dynamically:
type
TKind = enum
Kind1, Kind2
PTyp = ref TTyp
TTyp = object
case kind: TKind
of Kind1: ival: int
of Kind2: sval: string
# cannot use same name (val) for ival/sval => Error: redefinition of 'val'
proc newTyp(k: TKind): PTyp =
result = PTyp(kind: k)
var
t1 = newTyp(Kind1)
t2 = newTyp(Kind2)
t1.ival = 1
t2.sval = "foo"
# Try 1
proc ret_auto(typ: PTyp): auto =
case typ.kind
of Kind1: result = typ.ival
of Kind2: result = typ.sval
var x = ret_auto(t1) # Error: type mismatch: got (string) but expected 'int'
# So, alright. I cant delay to runtime to determine what type this proc has.
# Fair enough.
# Try 2
proc dyn_param(typ: PTyp, dyn: var auto) =
case typ.kind
of Kind1: dyn = typ.ival
of Kind2: dyn = typ.sval
var x : auto
t1.dyn_param(x) # Error: internal error: getTypeDescAux(tyExpr)
# Why does this fail? I would expect var dyn to become an int/string which propagates to x
# Try 3
template value(name: expr, typ: PTyp): stmt {. immediate .} =
var name: auto
case typ.kind
of Kind1:
name = typ.ival
of Kind2:
name = typ.sval
value(x, t1) # Error: internal error: getTypeDescAux(tyExpr)
# Same as 2, but i need an auto var to make "name" visible outside the case-of scope
Edited: can never check long posts enough.
type
PTyp[T] = ref TTyp[T]
TTyp[T] = object
val: T
proc newTyp[T]: PTyp[T] =
result = new TTyp[T]
var
t1 = newTyp[int]()
t2 = newTyp[string]()
t1.val=5
t2.val="test"
proc ret[T](obj: PTyp[T]): T =
result = obj.val
var
x = ret(t1)
y = ret(t2)
echo x, y
Your example works for compatible types:
type
TKind = enum
Kind1, Kind2
PTyp = ref TTyp
TTyp = object
case kind: TKind
of Kind1: ival: int
of Kind2: sval: int8
# cannot use same name (val) for ival/sval => Error: redefinition of 'val'
proc newTyp(k: TKind): PTyp =
result = PTyp(kind: k)
var
t1 = newTyp(Kind1)
t2 = newTyp(Kind2)
t1.ival = 1
t2.sval = 2
# Try 1
proc ret_auto(typ: PTyp): auto =
case typ.kind
of Kind1: result = typ.ival
of Kind2: result = typ.sval
var x = ret_auto(t1)
var y = ret_auto(t2)
echo x, y
type mismatch: got (Array constructor[0..1, typedesc]) but expected 'array[0..2, typedesc]'
You took away one item (float) and didn't change array size, so you got another error.
Thanks for your reply. I will try using generics then. :)
I was hoping i could eventually instantiate PTyp's in newTyp with some array.
So using generics :
proc newTyp(kind: TKind): PTyp[T] =
var ary: array[Kind1..Kind2, typeDesc] = [int, string]
result = new TTyp[ ary[kind] ]
This could be also done with a case-of block, but what confused me is that building an array of types is possible in the repl but not in normal code.