Nim:参数和可变性的地址 [英] Nim: Addresses of parameters and mutability

查看:122
本文介绍了Nim:参数和可变性的地址的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在努力确定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或其任何不位于refptr后面的地址,因为将值作为非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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆