0

I'm trying to call function on objects of specific type from the sequence, but compiler complains.

How to fix that? I need to get text property from the TextDoc objects.

type
  DocItem = object of RootObj
    tags: seq[string]

  TextDoc = object of DocItem
    text: string

  TodoDoc = object of DocItem
    todo: string

var docs: seq[ref DocItem]

proc to_ref[T](o: T): ref T =
  result.new
  result[] = o

docs.add TextDoc(text: "some doc").to_ref
docs.add TodoDoc(todo: "some todo").to_ref

for d in docs:
  if d of TextDoc:
    echo d.text

Error

Error: undeclared field: 'text'
Alex Craft
  • 13,598
  • 11
  • 69
  • 133

2 Answers2

2

To comment on the accepted answer, cast is an unsafe operation and should be avoided unless you have specific reason to use it. You could use a type conversion instead, like this:

for d in docs:
  if d of ref TextDoc:
    echo TextDoc(d[]).text

If you make TextDoc and TodoDoc ref object of DocItem then you can get rid of your to_ref proc, and write the loop like this:

for d in docs:
  if d of TextDoc:
    echo TextDoc(d).text

Or you could use an object variant, which is probably the most idiomatic approach:

type
  DocType = enum dtText, dtTodo
  DocItem = ref object
    tags: seq[string]
    case kind: DocType
    of dtText: text: string
    of dtTodo: todo: string

var docs = @[DocItem(kind: dtText, text: "some doc"),
             DocItem(kind: dtTodo, todo: "some todo")]

for d in docs:
  if d.kind == dtText:
    echo d.text
dsrw
  • 171
  • 2
1

The of conditional does not magically convert the type for the rest of the block, I'd cast the type, or write an additional helper proc to do it:

proc toTextDoc(thing: ref DocItem): ref TextDoc = cast[ref TextDoc](thing)
proc toTodoDoc(thing: ref DocItem): ref TodoDoc = cast[ref TodoDoc](thing)

for d in docs:
  if d of TextDoc:
    echo d.toTextDoc.text
  elif d of TodoDoc:
    echo d.toTodoDoc.todo
  else:
    echo "Not a ref?"
Grzegorz Adam Hankiewicz
  • 7,349
  • 1
  • 36
  • 78
  • Thanks, I also though about writing polymorphic code with `method` to call it and avoid explicit cast. Although it would be nice if in the future versions nim would support autocasting. – Alex Craft Aug 20 '20 at 20:13