vlang / v

Simple, fast, safe, compiled language for developing maintainable software. Compiles itself in <1s with zero library dependencies. Supports automatic C => V translation. https://vlang.io
MIT License
35.69k stars 2.15k forks source link

The "Array Slices" section in the V documentation is incorrect #21653

Closed go-xworkflow closed 3 months ago

go-xworkflow commented 3 months ago

Describe the issue

Array Slices A slice is always created with the smallest possible capacity cap == len (see cap above) no matter what the capacity or length of the parent array is. As a result it is immediately reallocated and copied to another memory location when the size increases thus becoming independent from the parent array (copy on grow). In particular pushing elements to a slice does not alter the parent:

mut a := [0, 1, 2, 3, 4, 5]
mut b := a[2..4]
b[0] = 7 // `b[0]` is referring to `a[2]`
println(a) // `[0, 1, 7, 3, 4, 5]`
b << 9
// `b` has been reallocated and is now independent from `a`
println(a) // `[0, 1, 7, 3, 4, 5]` - no change
println(b) // `[7, 3, 9]`

The result of running this code:

[0, 1, 2, 3, 4, 5]
[0, 1, 2, 3, 4, 5]
[7, 3, 9]

Are there any major errors in the V language documentation? The content described in the documentation is seriously inconsistent with the running results. This made me confused when I was learning V language. Please excuse my poor English

Links

https://docs.vlang.io/v-types.html#arrays

[!NOTE] You can use the 👍 reaction to increase the issue's priority for developers.

Please note that only the 👍 reaction to the issue itself counts as a vote. Other reactions and those to comments will not be taken into account.

go-xworkflow commented 3 months ago

V version V 0.4.6 736067d

Environment details (OS name and version, etc.) V full version: V 0.4.6 736067d OS: Manjaro Linux x86_64 Kernel: 6.6.32-1-MANJARO

go-xworkflow commented 3 months ago

Appending to the parent array may or may not make it independent from its child slices. The behaviour depends on the parent's capacity and is predictable:

mut a := []int{len: 5, cap: 6, init: 2}
mut b := unsafe { a[1..4] }
a << 3
// no reallocation - fits in `cap`
b[2] = 13 // `a[3]` is modified
a << 4
// a has been reallocated and is now independent from `b` (`cap` was exceeded)
b[1] = 3 // no change in `a`
println(a) // `[2, 2, 2, 13, 2, 3, 4]`
println(b) // `[2, 3, 13]`

The result of running this code:

[2, 2, 2, 2, 2, 3, 4]
[1, 3, 13]
go-xworkflow commented 3 months ago

You can call .clone() on the slice, if you do want to have an independent copy right away:

mut a := [0, 1, 2, 3, 4, 5]
mut b := a[2..4].clone()
b[0] = 7 // Note: `b[0]` is NOT referring to `a[2]`, as it would have been, without the .clone()
println(a) // [0, 1, 2, 3, 4, 5]
println(b) // [7, 3]

Code running results

[0, 1, 2, 3, 4, 5]
[7, 3]

However, I ran the following code and got the same result, which confused me and was totally inconsistent with what was described in the documentation.

mut a := [0, 1, 2, 3, 4, 5]
mut b := a[2..4]
b[0] = 7 // Note: `b[0]` is NOT referring to `a[2]`, as it would have been, without the .clone()
println(a) // [0, 1, 2, 3, 4, 5]
println(b) // [7, 3]

Code running results

[0, 1, 2, 3, 4, 5]
[7, 3]
spytheman commented 3 months ago

The documented example was done before we changed the default of the compiler to do a clone, and a notice that either an unsafe{} wrapper, or calling .clone() is needed to silence the notice.

i.e. the documented behavior in the example, currently needs mut b := unsafe { a[2..4] }.

I'll update the docs.

spytheman commented 3 months ago

Fixed in 0e543fb .