> Isn't this just duck typing? Don't other languages renowned for their type systems do this?
It's "structural subtyping", which is the type-safe equivalent of duck typing. It's a feature that allows implementations to exist without needing to know exactly every interface they implement. TFA's concern is purely theoretical.
> That's horrifying.
append() doesn't operate on arrays, it operates on slices. Arrays are fixed-length, contiguous blocks of memory that can't be appended to. Slices are backed by arrays, and if you append to a slice whose backing array is full, it will "grow" by allocating a bigger array elsewhere and copying the original data into it. This is a pretty standard data structure in most languages.
> This is a pretty standard data structure in most languages.
Yes, vectors are common, but they don't typically require compiler modifications to avoid mis-using them. In this case I'd make it super clear whether the method mutates the existing value or returns a new one, and "possibly both" seems like the worst of both worlds. If this behavior is preferred, it seems like `append` should take a handle to a slice pointer, possibly to a slice rooted in the stack, and write to it if replacing the underlying slice.
> Not to mention the ability to share a backing array between two "vectors" and to append to both. That's a Go innovation right there.
It's been pointed out in the comment right below this, but it is a bug if you do this. If the backing array has any free capacity the results will be very different from what you expect.
> append() doesn't operate on arrays, it operates on slices
If you go with most languages definition of "slice", that would be pretty horrible just by itself.
But, as you said, Go's definition is different (what is also bad, just not much):
> Slices are backed by arrays, and if you append to a slice whose backing array is full, it will "grow" by allocating a bigger array elsewhere and copying the original data into it
What would be pretty much like Java's ArrayList, or Python's list if it was designed on a sane way. So, just the name would be non-standard... But the container actually migrates when it is reallocated! That's a broken design in any language.
> If you go with most languages definition of "slice", that would be pretty horrible just by itself.
Most languages don't have a definition of "slice" at all.
> What would be pretty much like Java's ArrayList, or Python's list if it was designed on a sane way. So, just the name would be non-standard... But the container actually migrates when it is reallocated! That's a broken design in any language.
It's not broken, it's just fast and simple. But yes, it does require you to know that Go's slices are not exactly Python's lists (which do gratuitous copies). Java's implementation does an insert on the original list (both surprising and an unnecessary copy).
The feature leaves me 'meh'. I don't find slices as awesome as everyone is always saying, especially without negative indices.
I guess part of it it that it isn't always clear to me when you're dealing with a slice, or an array, or whatever.
I know, when it's confusing, there's always some reasonable sounding explanation after the fact, sure, but the whole thing feels like a confusing mess.
It's "structural subtyping", which is the type-safe equivalent of duck typing. It's a feature that allows implementations to exist without needing to know exactly every interface they implement. TFA's concern is purely theoretical.
> That's horrifying.
append() doesn't operate on arrays, it operates on slices. Arrays are fixed-length, contiguous blocks of memory that can't be appended to. Slices are backed by arrays, and if you append to a slice whose backing array is full, it will "grow" by allocating a bigger array elsewhere and copying the original data into it. This is a pretty standard data structure in most languages.