Can anyone give a mortal explanation of what these incoming changes mean / what my everyday code will look like if I take advantage of them? I see words like owned and lifetime and think Rust, which I love. But I don't see borrow etc. If I write code to use these new features, should I expect runtime performance gains, or will the gains be in memory used?
Are there docs for arc yet? This is the most relevant doc I've found yet: https://nim-lang.org/docs/destructors.html
That was a good post, it's just unclear to me what the concrete changes will look like for writing everyday code.
It'll look like this:
Yes, nothing will change for writing everyday code, that's a goal of ARC, as the replacement default GC. What ARC will bring are extra features that allows better optimization of Nim code, a more deterministic memory management strategy, better use of destructors so you don't have to close() things after you're done w them, finally make multithreading bearable in Nim, and so on...
It'll take a long time before ARC rises to be the replacement though, so don't worry about it too much unless you have specialized use case that would benefit from it
There are few changes required for everyday code. You must be aware not to create cycles. We have some primitive warnings for this that can detect some cases.
You can use sink and lent to help the compiler optimize but I'm also working on inferring these.
Borrowing is different from move semantics and refcounting, there is an RFC covering it.
However, the most common forms of borrowing might also be inferrable, consider for example:
let x = obj.field # borrow or copy can be left to the optimizer
f(obj) # can borrow if 'f' is .noSideEffect
use x
It's hard to ELI5 right now because it's all still WIP.
In theory, should not be many changes to how you write everyday code. You will notice Nim use less memory while still being on par with C/C++ performance for most common use cases. (YMMV of course.)
There are going to be a few new features that allow you to optimize your code like =sink, but that's an advanced optional feature.
There are a few domains that Nim is going to get way better at:
It's less like Rust and more like "C++" done right, imo. To quote Araq from IRC:
or if you know C++ well:
--gc:arc ~~ shared_ptr done right
--newruntime ~~ unique_ptr done right
-- Araq
The issue for me is that posts about --gc:arc still reference concepts like sink and lent parameters. These are described in the post about destructors, but, well, that document is not very understandable. Also, it is not clear whether the two mechanisms are going to coexist or --gc:arc will be a substitute for --newruntime (which then won't by ever enabled).
All of this is complicated by the fact that - as far as I understand - --gc:arc will not support exceptions as they are today, thus introducing other changes.
In short: I am lost. I don't know which mechanism will be used in place of a GC. I don't know if that requires me, as a library author, to introduce sink or lent parameters, which I still do not understand. (related to this, I have stopped writing Nim libraries, because I am unsure about its directions). I don't even know if existing libraries are supposed to be working with --gc:arc or --newruntime, so I don't submit issues about them.
I think we really need an ELI5 of these mechanisms, and this thread, until now, does not explain much.
Let me give some examples of what I do not understand in the destructors document. For instance, let's see sink parameters.
To move a variable into a collection usually sink parameters are involved.
Ok-ish. Let us see what this entails
A location that is passed to a sink parameter should not be used afterwards. This is ensured by a static analysis over a control flow graph.
Not sure what a location is, but if the compiler ensures it, seems fine.
If it cannot be proven to be the last usage of the location, a copy is done instead and this copy is then passed to the sink parameter.
So the compiler does not ensure this, after all. Looks like I can introduce copies by accidentally using a location (variable?) after putting it into a collection? Not sure if I am reading correctly
A sink parameter may be consumed once in the proc's body but doesn't have to be consumed at all. The reason for this is that signatures like proc put(t: var Table; k: sink Key, v: sink Value) should be possible without any further overloads and put might not take owership of k if k already exists in the table.
What is ownership? Is it defined elsewhere? It is not defined earlier in the document. As far as I know, Nim does not currently (v1) have a concept of ownership, so if it is relevant, it should be explained. I sort of understand the concept intuitively, and know a little Rust, but if Nim deviates from Rust (I assume it does) it should explain what it means for a a procedure to take ownership of a parameter.
The employed static analysis is limited and only concerned with local variables
So what happens for things that have a longer lifetime?
however object and tuple fields are treated as separate entities
This sentence is supposed to be explained by the following code sample, but I do not understand what the code sample is meant to convey
proc consume(x: sink Obj) = discard "no implementation"
proc main =
let tup = (Obj(), Obj())
consume tup[0]
# ok, only tup[0] was consumed, tup[1] is still alive:
echo tup[1]
Sometimes it is required to explicitly move a value into its final position:
Uh... sometimes when? Why should I explicitly move a value into its final position? The following code sample does not explain at all why here one should use explicitly system.move
proc main =
var dest, src: array[10, string]
# ...
for i in 0..high(dest): dest[i] = move(src[i])
And so on, and so on. Sorry for the rant, but I think an ELI5 is really needed, even if the whole concept is still in flux. At least the final vision should be clear.
In short: I am lost. I don't know which mechanism will be used in place of a GC. I don't know if that requires me, as a library author, to introduce sink or lent parameters, which I still do not understand. (related to this, I have stopped writing Nim libraries, because I am unsure about its directions). I don't even know if existing libraries are supposed to be working with --gc:arc or --newruntime, so I don't submit issues about them.
That's sad, please continue to develop libraries as we try hard to keep the code breakages to be minimal.
Not sure what a location is, but if the compiler ensures it, seems fine.
The manual does define what a "location" is fwiw. A location is an abstract memory cell.
Uh... sometimes when?
When the compiler cannot move it itself because the analysis can only reason about local variables effectively. It helps to read the document as a document and not as an unordered set of sentences.
I mean, ok, fair enough, one does not learn new features by reading their spec and we need better documentation but there is no reason to despair and stop developing Nim libraries.
there is no reason to despair and stop developing Nim libraries.
Thank you, I ensure you that I do not despair, but I feel a little lost with all the recent changes :-)