Do three dots contain multiple meanings?

Issue

As I recognize, “…” means the length of the array in the below snippet.

var days := [...]string { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" } 

On the other hand, “…” means unpacking the slice y to arguments of int in the below snippet, as I guess. I’m not really sure about this.

x := []int{1,2,3}
y := []int{4,5,6}
x = append(x, y...)

Now, the difference in the two meanings makes it hard for me to understand what “…” is.

Solution

You’ve noted two cases of ... in Go. In fact, there are 3:

[...]int{1,2,3}

Evaluates at compile time to [3]int{1,2,3}

a := make([]int, 500)
SomeVariadicFunc(a...)

Unpacks a as the arguments to a function. This matches the one you missed, the variadic definition:

func SomeVariadicFunc(a ...int)

Now the further question (from the comments on the OP) — why can … work semantically in all these cases? The answer is that in English (and other languages), this is known as an ellipsis. From that article

Ellipsis (plural ellipses; from the Ancient Greek: ἔλλειψις,
élleipsis, “omission” or “falling short”) is a series of dots that
usually indicates an intentional omission of a word, sentence, or
whole section from a text without altering its original meaning.1
Depending on their context and placement in a sentence, ellipses can
also indicate an unfinished thought, a leading statement, a slight
pause, and a nervous or awkward silence.

In the array case, this matches the “omission of a word, sentence, or whole section” definition. You’re omitting the size of the array and letting the compiler figure it out for you.

In the variadic cases, it uses the same meaning, but differently. It also has hints of “an unfinished thought”. We often use “…” to mean “and so on.” “I’m going to get bread, eggs, milk…” in this case “…” signifies “other things similar to breads, eggs, and milk”. The use in, e.g., append means “an element of this list, and all the others.” This is perhaps the less immediately intuitive usage, but to a native speaker, it makes sense. Perhaps a more “linguistically pure” construction would have been a[0]... or even a[0], a[1], a[2]... but that would cause obvious problems with empty slices (which do work with the ... syntax), not to mention being verbose.

In general, “…” is used to signify “many things”, and in this way both uses of it make sense. Many array elements, many slice elements (albeit one is creation, and the other is calling).

I suppose the hidden question is “is this good language design?” On one hand, once you know the syntax, it makes perfect sense to most native speakers of English, so in that sense it’s successful. On the other hand, there’s value in not overloading symbols in this way. I probably would have chose a different symbol for array unpacking, but I can’t fault them for using a symbol that was probably intuitive to the language designers. Especially since the array version isn’t even used terribly often.

As mentioned, this is of no issue to the compiler, because the cases can never overlap. You can never have [...] also mean “unpack this”, so there’s no symbol conflict.


(Aside: There is another use of it in Go I omitted, because it’s not in the language itself, but the build tool. Typing something like go test ./... means “test this package, and all packages in subdirectories of this one”. But it should be pretty clear with my explanation of the other uses why it makes sense here.)

Answered By – Linear

Answer Checked By – Senaida (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.