I was wondering, if there is an easy way to return something immutable from a function without copying it. To demonstrate my issue, I wrote this code snippet:
import random
type Big = object
c: array[10000, int]
# needs mutable seq[Big]
func get0(s: var seq[Big], i: int): var Big =
s[i]
# uses expensive copy
func get1(s: seq[Big], i: int): Big =
s[i]
# needs "internal" function, unsafeAddr, and is verbose
func getInternal(s: seq[Big], i: int): ptr Big =
unsafeAddr s[i]
template get2(s: seq[Big], i: int): Big =
s.getInternal(i)[]
var s: seq[Big]
s.setLen(100)
echo s.get0(rand(0..99)).c[0]
echo s.get1(rand(0..99)).c[0]
echo s.get2(rand(0..99)).c[0]
Currently, I use the get2 version. Is there a way to do this less verbose (similar to get0)? Or does the compiler not know enough about a non-var function parameter to know if it's even possible to not copy (hence the unsafeAddr)?
(Also, sorry for asking so many questions lately. Unfortunately, Google/DuckDuckGo currently doesn't help that much in many cases and the official documentation also not so much, if you don't know the necessary keywords already.)
You can use the lent keyword for getting a immutable reference, and you can override the =copy hook to see whether you're copying. Nim is intelligent enough with the lent annotation to copy if you call it to a var and then mutate it.
So an example of this is as follows:
import random
type Big = object
c: array[10000, int]
proc `=copy`(a: var Big, b: Big) =
echo "We Copied"
# needs mutable seq[Big]
func get0(s: var seq[Big], i: int): var Big =
s[i]
# uses expensive copy
func get1(s: seq[Big], i: int): lent Big = s[i]
# needs "internal" function, unsafeAddr, and is verbose
func getInternal(s: seq[Big], i: int): ptr Big =
unsafeAddr s[i]
template get2(s: seq[Big], i: int): Big =
s.getInternal(i)[]
var s: seq[Big]
s.setLen(100)
echo s.get0(rand(0..99)).c[0]
echo s.get1(rand(0..99)).c[0]
echo s.get2(rand(0..99)).c[0]
To your "sorry for asking so many questions" you could go to the realtime chats and ask simple questions.