I'm trying to make up my mind about Nim's policy behind expression has no address
. In particular, I have a C function which takes a pointer (+ length etc.) of some data buffer. I know that this function will not modify the data. Simplified:
type
Buffer = object
data: seq[float]
proc wrapperForCCall(buf: Buffer) =
# accessing either buf.addr nor buf.data.addr produces
# Error: expression has no address
# workaround:
var tmp = buf.data # costly copy
callToC(tmp.len, tmp.addr) # now it works
On the one hand this makes sense, since a parameter seems to behave exactly like a let
binding, which also "has no address". On the other hand, I'm puzzled by this statement in the manual:
var parameters are never necessary for efficient parameter passing.
As far as I can see, the only way to avoid copying the data is by either:
- passing the parameter as
buf: var Buffer
- passing a reference, i.e., using a
ref object
.
In both cases this suggests that my function modifies the data. Furthermore, it introduces mutability on the caller site (i.e. users can no longer use let bindings for their buffers). The key question for me is: Since "I know" that callToC
is read-only, can I convince Nim to allow both immutability without a copy? I see that this is dangerous, since I have to know for sure that the call is immutable. Thus, this would require some sort of "unsafe address" mechanism, allowing to force pointers to immutable data?
And my final mystery of parameter addresses: I tried to make the necessity of the copy explicit by changing the type to Buffer {.bycopy.} = object
. In this case the copy already happens at call time, and I would expect to have access to the address now. Why is the access denied in this case as well?
shallowCopy
here at all? If I understand you correctly (i.e., if the performance is similar to the no-copy case), it rather is a kind of "unsafeAlias"? – Merous