That seems like magic to me. I would prefer that type declarations not get conflated with value/reference semantics, since there isn’t a logical connection between them. Because at that point it isn’t a type declaration, it’s a type-and-this-is-copied declaration.
I don’t have a solid sense of what the rule should be, or I’d be willing to sketch it out. I don’t even have a very solid sense of what the current behavior entails, I watched the Killer Features video awhile back and perhaps I’ll return to it tonight.
I did hit a bug in my own code, where I took what turned out to be a copy of a slice. I had assumed that this meant that it consistently would be a copy, and fixed the problem by taking a pointer instead, but it does make me nervous if which is which turns out to be up to the whim of the compiler. I considered that a bug on my part, because in C, it would definitely be a copy, and I was just thinking in terms of languages with a more “object” and less “memory” model of program behavior when I wrote it.
It’s tough stuff to get right. Julia, for instance, has mutable and immutable structs, it’s a type-level distinction, and, being a dynamic language, mutable structs always go on the heap. It works… ok, mostly, but there are frequent posts on the forum about ways to work around the resulting lack of flexibility. But it does have the advantage of being a consistent rule: mutable structs have identity semantics, immutable structs have value semantics, and you can’t change them anyway. I don’t think it’s the right rule for a language with pointers, and where const-ness is a variable-level as well as type-level distinction.
So something like a @copy
intrinsic might turn out to be a punt, something the language shouldn’t need and which then remains around as a spandrel, or has to be removed again. But it would form a dual of taking a pointer: now you can guarantee shared memory, and you can also guarantee unique memory. That carves the problem at the joints, as it were, giving the design the flexibility to settle on what makes the most sense when neither of these things are the case.
My remaining observation here is that this ambiguity hasn’t created problems for me yet. The example code in this thread, for instance: while I know it’s intended to demonstrate something, making a local variable out of a global variable, passing it into a function, and then mutating the global variable directly in that function, would be anathema to me in any language. The code I write doesn’t have anything vaguely like that, so I haven’t tripped on it.
But I would indeed like to know for sure what happens if I write var a_slice: []const u8 = ref[idx];
. My presumption was that this is a copy, but it would be nicer to be sure of it, one way or the other.