This is why I love Go. Nobody was asking for this, but they took the time to do it right and continue to Push go as a memory safe, high-level systems language.
Java arrays are thin pointers to Array objects, which contain the length and data in the same place (on the far side of the pointer). Since thin pointers cannot tear and Array objects cannot be resized, Arrays themselves are always memory-safe in safe code.
Go slices are fat pointers to undecorated memory. The slice itself is a 3-tuple of pointer, length, and capacity. If you append to a slice that's already at capacity, the Go runtime will allocate new memory for you and return a new 3-tuple. If you assign that result to a variable that's also being accessed by another goroutine, the latter can observe the slice in an inconsistent state. It can, for example, see the old pointer but with the new length, allowing out-of-bounds access. None of this requires unsafe code.
The same issue applies to string and interface variables, which are also fat pointers.
Shared Go slices are a bad mix in concurrent code. This is a given. But its also not a fair comparison, you should instead compare java arrays to go arrays, not slices.
This goes for slices, strings and maps. Those a usually wrapped in a mutex, or used with sync primitives like sync.Map.
> Those a usually wrapped in a mutex, or used with sync primitives like sync.Map.
The same can be said of C or C++ constructs (and many "anti-Rust" people have historically said that) -- the point is that their use is not enforced by the language and so bugs can lead to panics.
I write a fair amount of Go and Rust so I really don't think either language's flaws are fatal, but it comes off as weirdly defensive to redefine memory and data safety to be "well if you use it properly it's safe". It's totally fine to say this is a problem the Go language did not find important enough to require compile time enforcement and so solving it is done by convention and testing with the race detector (which a similar answer C and C++ give to this problem).
u8 · · focus · HN ↗
__s · · focus · HN ↗
shikck200 · · focus · HN ↗
So whats your point here? Haskell?
beltsazar · · focus · HN ↗
You said that because you assumed Go is memory-safe in all conditions.
> Go is memory-safe
Yes, but only if there's no data race.
Go is not like Java. Java doesn't guarantee no data race, but when it happens, it's still memory-safe.
shikck200 · · focus · HN ↗
I fail to see how a racy Java program is more memory safe than a racy Go program?
kbolino · · focus · HN ↗
Go slices are fat pointers to undecorated memory. The slice itself is a 3-tuple of pointer, length, and capacity. If you append to a slice that's already at capacity, the Go runtime will allocate new memory for you and return a new 3-tuple. If you assign that result to a variable that's also being accessed by another goroutine, the latter can observe the slice in an inconsistent state. It can, for example, see the old pointer but with the new length, allowing out-of-bounds access. None of this requires unsafe code.
The same issue applies to string and interface variables, which are also fat pointers.
shikck200 · · focus · HN ↗
Shared Go slices are a bad mix in concurrent code. This is a given. But its also not a fair comparison, you should instead compare java arrays to go arrays, not slices.
This goes for slices, strings and maps. Those a usually wrapped in a mutex, or used with sync primitives like sync.Map.
cyphar · · focus · HN ↗
The same can be said of C or C++ constructs (and many "anti-Rust" people have historically said that) -- the point is that their use is not enforced by the language and so bugs can lead to panics.
I write a fair amount of Go and Rust so I really don't think either language's flaws are fatal, but it comes off as weirdly defensive to redefine memory and data safety to be "well if you use it properly it's safe". It's totally fine to say this is a problem the Go language did not find important enough to require compile time enforcement and so solving it is done by convention and testing with the race detector (which a similar answer C and C++ give to this problem).