@beltsazar 12d
Yeah, the most surprising thing about Go's slice expressions is that you can reslice a slice beyond its length, as long as it's still within its capacity.

I wonder how many off-by-one bugs have happened undetected because a slice is unintentionally resliced beyond its length. Instead of crashing, so that the issue is known early, the program will still run with inconsistent data.

@preseinger 12d
calling articles about language features and/or their implementations a "smell" is some pretty insane stuff

the slice behavior you demonstrate there is well-defined by the language spec, it's totally memory safe, it doesn't demonstrate memory corruption or anything like that

go is probably the most successful new language since java, if you don't like it that's fine, but it's nonsensical to call its design decisions "wrong"

@silisili 12d
I'm not sure how your snippet above exemplifies memory unsafety.

Concurrent access does let you hit some 'fun' behavior, but you have to be doing pretty dumb things to hit them. And while the implementation may be able to save you from something like that, such things would likely bubble up elsewhere(disk i/o, network i/o, etc) if doing that kind of thing.

@kosherhurricane 12d
TLDR:

The best part of Go is that there is very little magic in Go. If you understand that slices are just fat pointers implemented as a built-in, there is nothing confusing about them. I can understand every part of a Go program, all the way down to the language syntax that generate assembly. I don't have to be afraid of or be mystified by any language feature, because 1) there are few, 2) they are just programs implementable in Go. This does not happen with many languages.

Longer version:

Go didn't need to add slices as a language feature (it could have been a library function of containers, as fat pointers are not a new thing), but having it in the language makes using them easy. And not having generics at the start sort of forced their hand.

And as slices are just fat pointers to an underlying array, obviously it's not multi-thread safe.

So if you understand that slices are just C-style structs with pointer to data, a length counter and a capacity counter, then nothing in your example code is surprising. There is no hidden memory copy, no hidden synchronization lock to make it thread safe. And Go's a = append(a, item) now makes sense, because if 'a' grew in size, append would have to create a new underlying array, and a new slice struct with a pointer to new data. To me, it's much easier to reason about what the code is doing than other languages with Array types.

> nobody would ever design something like this without massive cognitive dissonance

Somebody did, without any cognitive dissonance. And I like it :)

> just copy and modify the previous industrial PL, C in this case

Go really wanted to be "A Better C". The language is not much larger than C, removed a bunch of C foot-guns, and it's as capable as Java, if not a bit more. I think the compromises Go made were well considered compared to other C family of languages.

@hamdouni 12d
Oh, I rather use this version :

  package main

  func main() {
    a := [2]int{1, 2}
    b := a[0:1:1]
    c := b[0:2]
    println(b[0], c[1])
  }