Nim:参数和可变性的地址 [英] Nim: Addresses of parameters and mutability
问题描述
我正在努力确定Nim在expression has no address
之后的政策.特别是,我有一个C函数,该函数接受某个数据缓冲区的指针(+长度等).我知道此功能将不修改数据.简化:
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
一方面,
是有道理的,因为参数的行为似乎完全像let
绑定一样,该绑定也没有地址".另一方面,我对手册中的这一说法感到困惑:
对于有效的参数传递,永远不需要var参数.
据我所知,避免复制数据的唯一方法是:
- 将参数传递为
buf: var Buffer
- 传递参考,即使用
ref object
.
在两种情况下,这都表明我的函数修改了数据.此外,它在调用者网站上引入了可变性(即用户无法再对其缓冲区使用let绑定).对我来说,关键问题是:既然我知道" callToC
是只读的,我是否可以说服Nim在不复制的情况下允许两个不变性?我看到这很危险,因为我必须确定该呼叫是不可变的.因此,这将需要某种不安全地址"机制,从而允许强制指向不变数据的指针?
最后一个参数地址的奥秘:我试图通过将类型更改为Buffer {.bycopy.} = object
来明确表示复制的必要性.在这种情况下,复制已在呼叫时发生,我希望现在可以访问该地址.为什么在这种情况下也拒绝访问?
您可以使用shallowCopy来避免buf.data
的深层复制,例如:
var tmp: seq[float]
shallowCopy tmp, buf.data
{.byCopy.}
杂注仅影响调用约定(即,对象是通过堆栈还是通过引用传递.
您不能使用buf
或其任何不位于ref
或ptr
后面的地址,因为将值作为非var参数传递可以保证被叫方不会修改争论.内置的shallowCopy
是一项不安全的功能,它绕过了以下保证(我记得建议将shallowCopy
应该正确重命名为unsafeShallowCopy
以反映这一点,并拥有一个新的shallowCopy
,其中第二个参数是var
参数也).
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?
You can avoid the deep copy of buf.data
by using shallowCopy, e.g.:
var tmp: seq[float]
shallowCopy tmp, buf.data
The {.byCopy.}
pragma only affects the calling convention (i.e. whether an object gets passed on the stack or via a reference.
You cannot take the address of buf
or any part of it that isn't behind a ref
or ptr
because passing a value as a non-var parameter is a promise that the callee does not modify the argument. The shallowCopy
builtin is an unsafe feature that circumvents that guarantee (I remember suggesting that shallowCopy
should properly be renamed to unsafeShallowCopy
to reflect that and to have a new shallowCopy
where the second argument is a var
parameter also).
这篇关于Nim:参数和可变性的地址的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!