> [!note] > [[Go]] popularized it as a de-facto dynamic array implementation, but this is applicable to other languages and libraries. # [[Go]] ![[Slice.svg]] Go popularized slices as they are the default type for dynamic arrays. Slices are quite strange as they behave differently than the usual `std::vector<T>` or `java.util.ArrayList<T>`. Conceptually, slice is a pointer to a range of an array. However, the `append()` built-in makes a slice like a vector. This results in very unusual syntax of `s = append(s, elem)` to perform an operation that would appear `vec.add(elem)` in many different languages. This ironically promotes immutable uses of `[]T`. The underlying elements can be modified, but `[]T` cannot be appended to modify the original slice. `*[]T` - pointer to slices - do allow this, but this is quite clunky to use and syntactically discouraged. Without strict notion of [[Rust]]-like ownership, it is very easy to introduce accidental data sharing via slices. This problem is present in most languages with different mitigations; C++ has references and `const`s to control mutability; Java heavily promotes immutability via `final`. However, Go doesn't have as big of immutability culture as C++. The same applies to any slice-like data structure in other languages. Rust formalizes this, but other languages provide them with sharp edges: - [[Java]]'s `substring` behavior - [link](https://www.javaadvent.com/2012/12/changes-to-string-substring-in-java-7.html). Previously, Java's substring shared the in-memory representation. However, starting from Java 7, this "optimization" was eliminated. - Another java example of [List.subList](https://docs.oracle.com/javase/8/docs/api/java/util/List.html#subList-int-int-). This method is explicit that the sublist is backed by the larger list. However, some semantic are ill-defined. --- > [!thought] > If you squint really hard, `append` looks like Lisp's `cons` and provides a very minimal persistent data structure like semantics.