See this thread:
https://forum.nim-lang.org/t/811
The experts there seem to imply that all objects behind the scenes are passed-by-pointer. Therefore, I conclude I don't need to use ref everywhere.
Is that true? And when do I use ref?
Large value types, over 24 bytes, are passed by pointer in the C/C++ backends. Smaller ones are passed-by-value, ultimately in machine code those are passed by registers on most (all?) combination of OS/CPU ISA/calling conventions.
Conclusion: In Nim, whatever your object, Nim will pass parameter the most efficient way and eliminates those low-level details worry
Value and references have wildly different use cases. The easiest way to choose one or the other is using analogies, for example between say a GeometricShape and a Person.
In your program:
In the first case you have instance equality, you are interested in the specific Person, in the second case you have structural equality, you are interested in properties.
Another term coming from finance is fungibility, a banknote is fungible because to pay $10, any banknotes worth 10 can be used. A person is usually non-fungible, because only the specific one chosen (for example for a job) can proceed, even if someone else has the same "properties" they are different.
Another aspect is assignment let b = a, with reference semantics, both a and b points to the same instance, aka they refer to the exact same instance. With value semantics, you construct a copy.
Reference semantics are used for resources that should be shared instead of copied: Person, NetworkConnection, DatabaseHandle, File, Thread.
Value semantics are used for interchangeable things: banknotes, triangles, ...
Thank you! What a great answer. My use case is a little fuzzy. Instead of mathematical objects like triangles I'm representing "Modules", "Categories", "Morphisms", etc. I think I'm going to use by-value for now, since although these are usually "infinitely sized" in abstract sense, to represent them it's just a few properties, like for morphism: it's the name "f", the domain object "X", and the codomain object "Y". But objects are also user-defined types in my Nim code.
Last question. __When a copy of an object is made, is it a shallow or a deep copy?__ A deep copy entails copying the object as well as copying all child objects, and their children and so on... So that seems expensive. If it's just a shallow copy, then I think my approach will work.
a shallow or a deep copy?
That is an interesting, but not that easy question. I think that topic is missing from my book, and even missing from the great https://zevv.nl/nim-memory/. Maybe covered in the new Book of Mr. Rumpf?
My conclusion is then I should use ref types almost everywhere.
For your application that may be true. Indeed a few people prefer using references always. My advice is more to use value types whenever possible, and to use ref types when there are good reasons for that, like many to one relations. Better efficiency when passing variables to procs should be never a reason to use ref types or var types, as the compiler handles the efficiency problem internally for us, i.e. passing data as hidden pointers when data size is larger than 3 times the float size. But I think I have discussed all that in detail in my book -- can not remember if that was discussed in the book of Mr. Picheta -- hopefully that is discussed well in the new "complete guide" of Mr. Rumpf.