type Matrix[M, N: static[int]] = ref tuple[p: ptr array[M, array[N, float64]]]
proc `[]`(m: Matrix, i, j: int): float64 =
m.p[i][j]
proc makeMatrix(M, N: static[int]): Matrix[M, N] =
new result
result.p = cast[ptr array[M, array[N, float64]]](alloc(M * N * sizeof(float64)))
for i in 0 .. < M:
for j in 0 .. < N:
result.p[i][j] = (i + j).float64
when isMainModule:
let m = makeMatrix(3, 5)
echo m[(1, 1)]
For those who are curious why I define Matrix this way: this type represents a managed pointer to an unmanaged pointer to a block of memory holding the entries of a matrix.
The reason I need this double indirection is that:
The idea is to use initializers and finalizers to tie the lifetime of the inner unmanaged pointer to the external managed pointer.
It works when Matrix is an object instead:
type Matrix[M, N: static[int]] = ref object
p: ptr array[M, array[N, float64]]
proc `[]`(m: Matrix, i, j: int): float64 =
m.p[i][j]
proc makeMatrix(M, N: static[int]): Matrix[M, N] =
new result
result.p = cast[ptr array[M, array[N, float64]]](alloc(M * N * sizeof(float64)))
for i in 0 .. < M:
for j in 0 .. < N:
result.p[i][j] = (i + j).float64
when isMainModule:
let m = makeMatrix(3, 5)
echo m[1,1]
andrea said: Nim won't let me take the addr of a managed ref
Huh? I'm fairly sure you should be able to get the address of a reference/address of the object a reference points to.
@Varriount: I cannot check right now since I do not have Nim on this computer, but looking at this section it seems that the addr is only defined for a var, so it would not be allowed for something declared with let, even if it is of ref type.
In fact, I discuss the problem in this question. The point is whether to use a normal ref, but have every procedure take a var even if the argument is not mutated, or hide a raw pointer behind a ref. If my understanding is correct (that is, there is no way to take the address of an immutable reference) then I prefer the raw pointer solution
Dereference the ref and then you can use addr on it:
addr(m[])
@def Thank you, this seems to work! It was not clear at all from the documentation! :-)
Is there anything unsafe I should be aware when doing so? As far as I know, the GC only starts when allocating, so if I take those addresses only to pass them to C functions, I should be ok, right? During the time the C function runs, the pointer will not be moved by the GC