Search code examples
nim-lang

How to create a ref object without either creating it twice or copying it?


It seems all the examples for creating a ref object will either create a copy or create a temp object and then throw it away. How do I create a reference to an object exactly once, without any copying? I'm explicitly trying to do this without a type Rect = ref object... style declaration.

It seems that new Rect is of type ref Rect. Clearly this does some allocating.

Each example I've seen does roughly this:

type Rect = object
  x: int
  y: int

# Basic, no refs; create and assign
var r0: Rect = Rect(x:10, y:20)

# The usual example; this seems to create extra object, copy values, then throw away
var r1: ref Rect = new Rect  # Creates default Rect
r1[] = Rect(x:10, y:20)      # Create desired Rect, copy, and throw away first Rect
                             # Or Create desired Rect, assign, and throw away first Rect

# This is what I'd like to do.  None of these attempts works
var r2: ref Rect = new Rect(x:10, y:20)

# Or this
var r3: ref Rect = ref Rect(x:10, y:20)

# Or this
var r4: ref Rect = ref new Rect(x:10, y:20)

# Or this
var r5: ref Rect = Rect(x:10, y:20)

So is it possible to declare a ref and assign it to a new instance without copying and/or creating extra throw-away objects? It would be nice to do this in one line, but not a hard requirement.

thanks


Solution

  • As far as I know all allocated reference objects are initialised to zero. If you want a pseudo constructor like way of allocating and initialising ref objects you can write one yourself, there's nothing special about them. See the following example, where first var is taken from your question, second assigns manually to avoid creation of object, and the third uses a manually created function to allocate and assign. It is a bit low level that you need to create this function, but on the other hand you can go crazy with this and do error checks or other things other languages prevent you from doing because they have stricter rules for constructors:

    type Rect = object
      x: int
      y: int
    
    # Basic, no refs; create and assign
    var r0: Rect = Rect(x:10, y:20)
    
    var r1: ref Rect = new Rect
    r1.x = 15 # By default nim dereferences
    r1[].y = 30 # But you can still use it manually
    
    echo "r0 => ", r0
    echo "r1 => ", r1[] # You need to explicitly dereference here though
    
    func allocRect(x: int, y: int): ref Rect =
      ## Allocates memory for Rect and assigns some values to it.
      result = new Rect
      result.x = x
      result.y = y
    
    var r2: ref Rect = allocRect(30, 40)
    
    echo "r2 => ", r2[]
    

    The output of this example is:

    r0 => (x: 10, y: 20)
    r1 => (x: 15, y: 30)
    r2 => (x: 30, y: 40)