First of all thanks to OP redditor and everyone else for this thread. I have been curious about Nim for a long time and interested in its balance of great features, nice syntax and maybe some rough edges.
Please forgive my completely uninformed participation, as someone entirely new to Nim, but I also wanted to understand a bit how it works (I previously asked a [related question](https://www.reddit.com/r/nim/comments/fuu8ps/what_would_be_the_nim_equivalent_of_a/) on Reddit a few months ago and the answer was basically "use marshal"). My impression is that Nim behaviour here seems a bit inconsistent... import json type DocItem = object of RootObj tags: seq[string] TextDoc = ref object of DocItem text: string TodoDoc = ref object of DocItem todo: string var docs: seq[ref DocItem] let textdoc = TextDoc(text: "some doc", tags: @["help"]) let tododoc = TodoDoc(todo: "some todo") docs.add textdoc docs.add tododoc echo textdoc[] # (text: "some doc", tags: @["help"]) echo textdoc.text # some doc echo tododoc[] # (todo: "some todo", tags: @[]) echo tododoc.todo # some todo # ...all good so far echo docs[0] of TextDoc # true echo docs[0][] # (tags: @["help"]) # 🤔 we are missing the `text` field # must be because type of var docs: seq[ref DocItem] # but above we just said this element is still "of TextDoc" echo docs[0].text # does not compile: # Error: undeclared field: 'text' Run It seems confused about whether elements of `docs` sequence have been truncated down to `DocItem` or still have their full type. I'm sure someone who knows Nim better can explain the semantics here? And if it's going to squash them to fit the type of the sequence then it would be useful if Nim had proper sum types so you could widen the definition of the `docs` type. We can find a description of two options for heterogenous sequences here: [https://forum.nim-lang.org/t/4233#26367](https://forum.nim-lang.org/t/4233#26367) The second is the one above ("boxed types") that doesn't work properly. The first is using "object variants", which seems to be what Nim has instead of sum types. [https://github.com/nim-lang/Nim/wiki/Common-Criticisms#sum-types-are-weird](https://github.com/nim-lang/Nim/wiki/Common-Criticisms#sum-types-are-weird) The need to have a "discriminator" field to use in the `case` means we now have to make a custom `%` proc for our variant type, so that we can omit that superfluous field from the serialized output. So you end up with this: import json type DocKind = enum BaseDoc, TextDoc, TodoDoc DocItem = object tags: seq[string] case kind: DocKind of TextDoc: text: string of TodoDoc: todo: string else: discard var docs: seq[DocItem] docs.add DocItem(kind: TextDoc, text: "some doc", tags: @["help"]) docs.add DocItem(kind: TodoDoc, todo: "some todo") proc `%`*(doc: DocItem): JsonNode = result = case doc.kind of TextDoc: %* {"text": doc.text, "tags": doc.tags} of TodoDoc: %* {"todo": doc.todo, "tags": doc.tags} else: %* {"tags": doc.tags} echo %docs Run I spent a long time trying to use `fieldPairs` in the `%` proc and just filter out the `kind` field, but I could not get anything to work (it seems `fieldPairs` is some kind of fragile magic that only works in a for loop syntax position and gives an error in other places) I'd love to know if there is a way to write this `%` proc that doesn't need to be updated each time you add a new kind to `DocKind`. It is fairly cumbersome as is.