3

There are various libraries in nim that return actual objects, rather than references. Sometimes I want an object on the heap (regardless of efficiency) -- for instance when I have a generic procedure that expects a ref to an object.

The only way to construct an IntSet on the heap I have found is:

proc newIntSet() : ref IntSet =
  new(result)
  assign(result[], initIntSet())

This seems to work, but feels like a hack. I worry if it only seems to work. (Are the structures copied by "assign" properly cleaned up?) Is there a better way? Is there a more generic way that will work with other objects?

shaunc
  • 5,317
  • 4
  • 43
  • 58

1 Answers1

5

Your code is perfectly valid. The resulting reference will be subject to garbage collection as any other referefence.

If you find yourself doing this often, you can define the following makeRef template to get rid of the code repetition:

template makeRef(initExp: typed): expr =
  var heapValue = new(type(initExp))
  heapValue[] = initExp
  heapValue

Here is an example usage:

import typetraits

type Foo = object
  str: string

proc createFoo(s: string): Foo =
  result.str = s

let x = makeRef createFoo("bar")
let y = makeRef Foo(str: "baz")

echo "x: ", x.type.name, " with x.str = ", x.str

Which will output:

x: ref Foo with x.str = bar
zah
  • 5,314
  • 1
  • 34
  • 31
  • Ok ... hmm... will this work with IntSet (for instance) though: you use `heapValue[] = initExp`. Could this cause problems because the stack value returned by `initExp` is copied using a shallow copy (rather than using `assign`), then if the object has a destructor it will be run when the stack object goes out of scope on the elements pointed to by the heap object? – shaunc Apr 29 '16 at 00:30
  • Nim uses a technique similar to C++'s [return value optimization](https://en.wikipedia.org/wiki/Return_value_optimization). If you look at the generated code, you'll see that the memory for the Foo object is first allocated on the heap and then the address is passed to the createFoo function, which performs the construction in place. There is no copy operation in this particular case. – zah Apr 29 '16 at 01:01
  • You didn't answer the question about destructors.... Trying myself I get the warning (twice!): "usage of a type with a destructor in a non destructible context." if I use "makeRef" with a object with a destructor. So it does seem that nim *thinks* the object is on the stack, at least, weather or not it actually puts it there. Perhaps this will be resolved somehow as destructors are {.experimental.} – shaunc Apr 29 '16 at 02:22