I have a root object like this, with some properties like name, category etc:
type MyRoot* = ref object of RootObj
name*: string
category*: string
active*: bool
And more objects similar to this that inherit from root object and also have their own properties...
type Get_Word* = ref object of MyRoot
hypenated_as_one*: bool
i then add each object i want to use to this seq
var seqOfObjects: seq[MyRoot] = @[]
So my question is:
How can i find out what properties are in each object that are stored in the above seqOfObjects?
I have tried various ways but all i am getting are errors similar to these:
for n,v in fieldPairs(seqOfObjects):
Error: type mismatch: got <seq[MyRoot]>
for v in fields(seqOfObjects):
Error: type mismatch: got <seq[MyRoot]>
i have even tried this:
for o in items(seqOfObjects):
for v in fields(o):
but get:
Error: type mismatch: got <MyRoot>
Is there some thing i am missing or some other way to access those properties? Thanksyou can do it like this:
type
CmsWidget* = ref object of RootObj
strVal*: string
Slug* = ref object of CmsWidget
slugVal*: string
Text* = ref object of CmsWidget
textVal*: string
var elems: seq[CmsWidget] = @[
Slug(strVal: "str", slugVal: "slug"),
Text(strVal: "str2", textVal: "text")
]
for elem in elems:
if elem of Slug:
echo cast[Slug](elem).slugVal
elif elem of Text:
echo cast[Text](elem).textVal
Do we really should use an ugly cast here like your
echo cast[Text](elem).textVal
Is the performance benefit that large compared to a clean type conversion
echo Text(elem).textVal
Of course, you can say that the cast is safe, due to the "of" test before. But it is so UGLY!
hi kobi, yes the reason i asked is because i am basically trying to restore object properties that have been previously saved, say to disk, so to restore them i need the objects property and its type.
The objects are actually saved in Json format (in one file), and i did try using the 'to' macro in the Json library to restore them but without success.
Its no problem to state each objects property to restore it, just long winded with many different objects.
Json library to restore them but without success.
I would guess your problem is with inheritance and
Restriction: For objects their type is not serialized. This means essentially that it does not work if the object has some other runtime type than its compiletime type.
That is stated for the marshal module, but seems to apply for all serialization libs.
Hi Stefan, yes it looks like my problem is to do with storing different data types into the same sequence and then trying to save that then restore it.
I could (although it would require a bit of a rewrite) try storing each of my types into sequences of the same type but each could have a new integer property that tells me there original order.
I say this because its important i restore each object in the same order it was saved in, in other words order is important as well.
Maybe you can use object variants, see
http://ssalewski.de/nimprogramming.html#_object_variants
JSON should work with object variants, but I have not yet tested that. The disadvantage is that with object variants all instances consume as much RAM as the largest one does, as all must have the same size. But when the objects are small, or have similar size, then object variants should be an option.
try storing each of my types into sequences of the same type
That is what I am currently doing with my SDT program. The top level objects are stored all in one RTree, which is internally a seq of base type RootRef with a bounding box for fast localization for all the types. But I group objects into Group objects, and that Group has fields like seq[Line], seq[Circ], seq[Pin]... And I put all toplevel elements into such a toplevel group for storing them as JSON. Having the elements in homogeneous sequences has some advantages, e.g. for z-ordering, or drawing as all Pins have same color, so I can set color once and then draw all the Pins. For fast localization on the other hand I have to store all the toplevel elements in a single RTree.
Maybe, when I later should find out that most elements have nearly the same size, then I may use object variants instead of inheritance.
No, im using the default Code Runner in VSCode which is this:
nim compile --verbosity:0 --hints:off --run ........filepath..........
I need debug info in there anyway since my program is in its early stages, plus i'm not sure if -d:release turns off bounds checking etc?
-d:release does not turn off bounds checking. You can see this by looking at the nim.cfg for your nim installation (for choosenim,``~/.choosenim/toolchains/nim-1.4.8/config/nim.cfg``)
74 │ @if release or danger:
75 │ stacktrace:off
76 │ excessiveStackTrace:off
77 │ linetrace:off
78 │ debugger:off
79 │ line_dir:off
80 │ opt:speed
81 │ define:release
82 │ @end
You can check memory usage in release mode and then go back to debug modeUnfortunately switching to -d:release crashes the app without any error messages or gives me this error message then crashes:
Error: SIGSEGV: Illegal storage access: (Attempt to read from nil?)
The same code works without crashing or any error messages when not using -d:release
The problem is the garbage collector!
If i switch it off then my app runs without crashing (reason for crashes given above)... its using 3GB of ram though which is obviously no good .... any suggestions on how to procede?
Yes, we saw your update.
But your main conclusion is wrong with a large probability, it is not a bug of the GC.
When our C code crashes when we call dealloc() or free(), then generally the bug is not in these two functions, but in our own code. Nim's various garbage collectors has been already tested a lot. The fact that one of them do not crash with your code just means that that one hides the bugs of your code.
Whenever your code contains casts, use of ptr and addr calls, or uses foreign C libs, then that code can introduce serious bugs. You should try to shrinkt your code until it gets tiny and the source of the crash becomes obvious. (It is some work, I did it last time some months ago, cause was an invalid cast between ref object and RootRef. Took me two to three full days, but was indeed my own bug.)
Well i would have thought that the end result of all garbage collectors is the same... to free up memory that is no longer being used?
So how can a garbage collector that stomps all over memory that is obviously still being used be correct?
The most annoying thing is the fact that my code seemed to be running perfectly fine until i switched to using -d:release, i would have thought that if there was a possible bug in my code, especially one that can fully crash the app i would have had some sort of warning so that i could correct it before switching to -d:release?
Your assumption is generally right, but only when you use only clean Nim code. Not when you use C libs, casts, addr() and pointers. With the later you can do very dirty things, you can un-intentionally overwrite references for example. And then, when the the GC tries to free memory pointed to by that references the wrong memory address is used. Different GC's may react different to such errors. Your observation that the error does only occur with -d:release may indicate only that the error is somehow hidden without -d:release. Debugging code which is included in the executable without -d:release moves memory addresses, so the buggy code may still overwrite data in illegal ways, but when it only overwrites unimportant data, then you may see no crash.
You should try to get your program compile with ARC. Good Nim software compiles fine with ARC. And then you can use the compiler option --gc:arc -d:useMalloc and run your executable with valgrind, which may give you a detailed error report.