First off, before I explain, please understand that this ship has sailed - changing assignment semantics of strings and sequences would cause breakages with all existing code (and not simple 'error' breakages, but bugs).
You are correct in that sequences and strings have assignment semantics different from those of other ref types. Unlike a reference type whose reference is copied on assignment, sequences and strings have their entire data structure copied. F̶o̶r̶ ̶s̶t̶r̶i̶n̶g̶s̶,̶ ̶t̶h̶i̶s̶ ̶i̶s̶ ̶h̶o̶w̶ ̶i̶t̶'̶s̶ ̶d̶o̶n̶e̶ ̶i̶n̶ ̶m̶o̶s̶t̶ ̶l̶a̶n̶g̶u̶a̶g̶e̶s̶ ̶(̶e̶v̶e̶n̶ ̶j̶a̶v̶a̶)̶ Nope, I was wrong. It's debatable whether taking such a stance is 'correct' or not - it's largely down to preference. I was going to post a more detailed explanation of why Nimrod uses assignment semantics, but it really just boils down to 'just because' and 'it might make more sense and cut down on bugs' - hardly what I would call a strong argument.
Do realize though that you can use the shallow procedure in the system module to mark a sequence or string instance as having reference assignment semantics. You can also use shallowAssign procedure to do this on a case-by-case basis, for more granularity.
Sorry, I meant shallowCopy. Shallow does work with strings, but only when the strings are not in the top-level scope:
template mainImpl =
var a, b, c: string
a = "Hello"
shallow(a)
b = a
c = b
echo(repr(a))
echo(repr(b))
echo(repr(c))
proc main = mainImpl()
echo("In procedure scope:")
main()
echo("\nIn global scope:")
mainImpl()
Shallow doesn't work with strings at the top level, in order to maintain GC safety (I think, this might be a bug).
Araq: getRefCount is useful for debugging code that interfaces with C, where code might call the reference count increase or decrease procedures in order to keep a structure in memory.
proc test() =
var str1 = "abc"
var str2: string
shallowCopy(str2, str1)
str2[0] = 'x'
str2[1] = 'y'
str2[2] = 'z'
echo str1 # xyz
echo str2 # xyz
int[] arr1 = {0,0,0};
int[] arr2 = arr1;
arr2[0] = 1;
System.out.println(arr1[0]); // 1
You need to use System.arraycopy explicitly to copy.
Sorry about nit-picking. Its just slightly "surprising".
For strings, this is how it's done in most languages (even java).
Are you sure? Java strings are immutable so I believe only the reference is copied. Ditto for python and lua and c#.
Gah, you were right. For the record, I did sorta check - I tried this out in python, and looked up whether strings were copied on assignment in java, and misinterpreted the results for each. I've struck out my previous comments.
For what it's worth though, Python and Java have immutable strings, Nim does not. I don't know whether one is objectively better than the other, this is just how it is.
@vbtt "Stupid question.. Can I define a var to be of type ref string?"
A string already is a reference. You need to shallowCopy instead of = to make it act like one.
proc test() =
# str1, a reference points to a heap object
var str1: string = "I am a string literal"
echo sizeOf(str1) # 4 bytes
# array of million string references
var arrayOfStringRefs = newSeq[string](1_000_000)
for i in arrayOfStringRefs.low .. arrayOfStringRefs.high:
# ref in array set to point to what str1 points at
shallowCopy(arrayOfStringRefs[i], str1)
# str1 is dereferenced and its pointed at
# string is modified to be Z.
str1.setLen(1)
str1[0] = 'Z'
# refs in array also point to the same string
echo arrayOfStringRefs[0] # Z
echo arrayOfStringRefs[500_000] # Z
test()