Translating this Python code
a = [1, 2, 3]
b = a
b.append(4)
print(a) # [1, 2, 3, 4]
to Nim requires quite some manual dereferencing:
var a = new seq[int]
a[].add [1,2,3]
var b = a
b[].add(4)
echo a[] # @[1, 2, 3, 4]
which can be avoided by using the experimantal pragma
{.experimental: "implicitDeref".}
var a = new seq[int]
a.add [1,2,3]
var b = a
b.add(4)
echo a # @[1, 2, 3, 4]
I wonder why automatic dereferencing for the first proc argument is not the standard, whereas implicit dereferencing of ref object fields is performed.
Further after seeing this recent pull request without any discussion in the conversation tab I'm a bit unsure about using this IMO nice feature.
So translate it to idiomatic Nim.
var a = newSeq[int]()
a.add [1,2,3]
var b = move a
b.add(4)
echo b # @[1, 2, 3, 4]
Aliasing is very hard to reason about anyway, or in Python-ese "aliasing is implicit behavior and explicit is better than implicit". Funny how Python's catchphrase contradicts Python's design. Every single time.
Thanks for the quick reply and the code example, although it does something rather different.
The Nim Manual reads
References (similar to pointers in other programming languages) are a way to introduce many-to-one relationships. This means different references can point to and modify the same location in memory (also called aliasing).
So I thought aliases are also considered idiomatic Nim. Making fun of some other programming language does not help either, I just used some minimalistic code example, in the hope of making the desired outcome more clear.
So is the experimental "implicitDeref" going away?
It's mentioned in the Roadmap for Nim issue on the RFCs repo under "cleanup of experimental features". The problem is that even though this feature may be useful, there's no guarantee the maintenance cost that comes with it is worth it.
In the case of this issue, there are 0 issues <https://github.com/nim-lang/Nim/issues?q=is%3Aissue+implicitderef>_ about it, open or closed, either meaning it works fine, or no one uses it because no one wants to bother turning on the experimental switch or they just don't know it exists. IMO it's fine to let unproblematic experimental features sit like this as long as they don't have a huge footprint in the compiler.
I asked about implicitDeref a while back. The verdict was: it seems like a nice feature but it doesn't jive well with others in its current form. For example a var parameter is supposed to never be nil but with implicitDeref it could be!
And yeah, ref seq is indeed unidiomatic, even though it's correct if you're aiming for a 'direct' translation from Python. I'd say the [] is pretty helpful here to me as the reader, as it emphasizes that something unexpected is going on (this is no ordinary seq)
So I thought aliases are also considered idiomatic Nim.
Aliases and reference's are idiomatic in Nim but usually as defined on the object type. As @exelotl5h mentioned ref seq in regular code isn't idiomatic.
Some stdlib containers provide both value and ref types like Table vs TableRef. seq is a bit of an outlier though.
In practice Nim code relies on the default seq behavior not aliasing. Personally I find it prevents annoying bugs where Python libraries mutate your list (seq) on you. It's a guessing game. Nim is able to express a mutable seq argument using arg: var seq. Likely that's what @araq was talking about.
So is the experimental "implicitDeref" getting removed in the future? Does using it introduce some problems?
It's more like premature optimization. Generally the normal seq behavior is better.
If you're porting Python code you could use var seq or even wrap the seq in a ref object. It's not quite as nice but works:
import sequtils
type PySeq[T] = ref object
seq*: seq[T]
proc newPySeq[T](val: varargs[T]): PySeq[T] = return PySeq[T](seq: val.toSeq())
var a = newPySeq(1,2,3)
var b = a
b.seq.add(4)
Thanks for all the replies. I should not have used seq in the explaining example code, as it diverted the responses in that direction.
The actual concern was why implicit dereferencing of ref object fields is performed, but not for procs on that ref object.
Instead of requiring ptr T not nil for auto-deref to solve potentiall issues with it (as suggested here), it seems that it gets now removed completely as written in the roadmap.
Another peculiarity to remember when learning Nim.