Hi, I just started learning Nim and already like it a lot.
Having read about ref types and the proc naming convention, I wonder if newSeq() is named inconistently, maybe because of historic reasons, or if I misunderstand something:
import tables
var tbl1 = initTable[string, int]()
var tbl2 = tbl1
tbl1["a"] = 1
echo tbl1, " ", tbl2
echo typeof(tbl1)
echo()
var tbl3 = newTable[string, int]()
var tbl4 = tbl3
tbl3["a"] = 1
echo tbl3, " ", tbl4
echo typeof(tbl3)
echo()
var seq1 = newSeq[int](5)
var seq2 = seq1
seq1[2] = 5
echo seq1, " ", seq2
echo seq1.typeof
{"a": 1} {:}
Table[system.string, system.int]
{"a": 1} {"a": 1}
TableRef[system.string, system.int]
@[0, 5, 0] @[0, 0, 0]
seq[int]
Thanks for the quick reply and clarification. I know, changing such fundamental things is not possible because of existing code, and being so used to it probably make it seem a non-issue.
OTOH, having inconsistencies in fundamental places confuse new users which are trying to learn Nim and "get" it (the value-type/reference-type thing), quite a bit.
Would having an initSeq synonym for newSeq be possible, and use the consistent naming in the tutorials and manuals? Like typeof replaced type and is mentioned in the manual being discouraged?
I must say that I had the exact same thought when I started learning nim. Personally I like the idea of adding initSeq as an alias. It’s true that that would mean that there would still be a newSeq that would not return a ref but maybe that could be fixed at some point?
As a less ambitious alternative, or perhaps in addition to the above, maybe a note about this could be added to the docs of newSeq and to the tutorial.
The other option is to adopt new and init the following way:
func init(T: type Xxx, a, b: int): T = T(
x: a,
y: OtherType(s: b) # Prefer Type(field: value)-style initialization
)
let m = Xxx.init(1, 2)
# `new` returns a reference to the given type:
func new(T: type Xxx, a, b: int ): ref T = ...
# ... or `init` when used with a `ref Xxx`:
func init(T: type (ref Xxx), a, b: int ): T = ...
Thus, newSeq, newException and so on would be deprecated in favor of using either object construction syntax ((ref ValueError)(msg: "...")) or seq[byte].new(42) for ref seq and seq[byte].init(42) for seq.
See also https://status-im.github.io/nim-style-guide/language.objconstr.html
i am not really sure that i am a fan of adding init and new as it would give the false impression of how constructing objects works in Nim.
an alternative convention: init and new in this case do not refer to copying semantics but whether or not the object is heap-backed.
there once was a point where it was easier to have momentum on stuff like this, in spite of w/e significance it has and whatever degree of relation it has to the "bigger picture" of the language as a whole, primarily because there were fewer affected parties using the language in general. this is not really helped by the fact that newSeq is probably one of the most commonly used procedures in the whole language.
something that i think deserves to be said here: development on this language moves a lot faster if you have an actionable PR in hand. way easier to assess the damage of any one specific alteration and stamp a "yes" or "no" on it if you are move into the code that much sooner. the secret weapon of the "work in progress" is that it slices through the sludge of bikeshedding by rendering what may have been once "concerns" into immediate consequences.
For this reason I was often confused learning nim if init implied I should pass a value to be initialized C-style, or if it instead actually created something for me. I know there's the existing low-level memory function of the same name, but I like the idea of a version of Nim that uses these words consistently, such as create(), {.noinit.}, new() . It would also make nim easier to teach!
I recently had a use case where I needed for template reasons init style parse(typedesc[T], v) versions of the strutils parsing functions. Another case I was desiring uniformity but I'm this case for composition.