Go is lack of Tuple type since first release, variadic return variables can solve this in a strange way. (At least in my thinking, what's wrong can be pointed out)
Recently a series proposals to add iterator to go, and introduce a trick type Seq2
, this make thing even worse, we can imagine that in the near future, there may lots of trick types in std library, this should be what everyone doesn't want to see.
So I propose add the long time missing type - Tuple
to go, then the Seq2
can write to Seq[(K, V)]
, imagine ()
make a list type into tuple type.
Access tuple field using index number.
In function return values, we can treat it as tuple implicitly, so we can write this:
func x() (int, string) {
...
}
func y() {
ret := x()
print(ret.0)
print(ret.1)
}
Related Iterator Proposal: #61897 and others ...
Comment From: zephyrtronium
Maybe aside from syntax, this is #32941. Per https://github.com/golang/go/issues/32941#issuecomment-509344540:
If we introduce a new kind of type we need to discuss things like how to initialize them, how to convert them, how to decompose them, and what composite literals look like. It seems to me that most of the answers for a
tuple
will be the same as the answers for astruct
. That suggests thattuple
doesn't add much to the language. So let's think about whattuple
does add, and it would take to make that work withstruct
.
Comment From: apparentlymart
As noted above, a tuple type is very similar to a struct type, and so I think it's worth enumerating some of the ways that struct types are awkward to use, which a separate tuple type kind might therefore address.
Here are my attempts: 1. Anonymous struct types are very verbose to use as part of a function signature, because the whole type must be written out to construct a value of the type:
```go
Foo(struct { a int, b string }{ 4, "hello" })
```
- When writing mechanical building blocks that are not part of any specific domain model, it's sometimes difficult to select good field names, because they literally represent "the first value", "the second value", etc, with the meaning decided by the provider or recipient of the value.
- In particular, Go's support for multiple return values from a function is not coherent with most other language features. Not all results from a function can be sent directly through a channel, stored in an array, etc. Generic functions tend to end up having quite different signatures than non-generic functions where the number of results isn't fixed as part of the signature.
I'm not intending to make any statement about how important these items are, only to start enumerating them as part of exploring whether tuple types would add enough value to be worth the additional language complexity.
Comment From: jimmyfrasche
33080 wasn't about tuple types per se but it ended up talking about them a lot
Comment From: apparentlymart
My point 1 above could potentially be addressed with a new syntax for assigning an anonymous struct value, where the field types get chosen automatically rather than being written explicitly.
I'm not sure exactly what syntax would make sense for this. Here's an initial example that I expect everyone to hate just because, as Ian often points out, it's helpful to have something horrible for everyone to agree they dislike. 😀
struct{...}{Name: "foo", Age: 6}
The ...
here is intended to represent automatically deciding the type of each field using the same rules as for the :=
declaration-and-assignment operator.
If the second set of braces didn't have any field names then this would essentially be a tuple type, since the compiler would need to choose some field names automatically, although automatically selecting names that are valid identifiers (rather than integers) would avoid introducing a new field access convention. Choosing names that start with letters would, in particular, force making a decision about whether they are uppercase or lowercase and thus whether the fields are exported. Since anonymous struct types don't have methods, I assume they would be exported since otherwise the fields would only be accessible in the package where the struct was written.
Again I want to reinforce that I'm showing a hypothetical "anonymous struct that acts like a tuple" just as an initial hypothetical answer to how these concerns could be met without introducing a new kind of type. I don't actually like it, and invite alternatives that are less clunky but still ultimately yield something that is compatible with an anonymous struct type, and therefore hopefully a new enough take on the previous proposal (addressing the concerns raised there) to make it worth revisiting.
Comment From: seankhliao
see also #12854 #35304
Comment From: apparentlymart
Another "what if this were essentially just syntactic sugar for struct types" hypothetical:
Predeclared identifiers tuple2
, tuple3
, ...tupleN
which the compiler treats as generic structs with N
type parameters and N
fields. For example, here's what tuple3
could be treated as:
type tuple3[T0, T1, T2 any] struct {
F0 T0
F1 T1
F2 T2
}
I'm imagining these predeclared identifiers being a special case where they behave as if there are an infinite number (or perhaps 2...MAX_INT
:man_shrugging:) of such identifiers, even though it would not be practical to write out that many declarations as literal source code. I expect that's unprecedented, so that would be one immediate downside of this idea.
The above alone would be just as cumbersome as an anonymous struct type, but with the information moved about a little and some different punctuation:
tuple2[string, int]{"hello", 4}
Combined with something like #61731, the explicit type parameters can vanish from the supposed-idiomatic form:
tuple2{"hello", 4}
At that point the only remaining redundancy is specifying the arity: the number of expressions inside the braces implies that this is tuple2
, so it would ideally not be necessary to write that out. And so I think that is the place where some syntactic sugar could potentially be helpful. e.g.:
[string, int]
as a shorthand fortuple2[string, int]
(a type)("hello", 4)
as a shorthand fortuple2{"hello", 4}
(a value) to be interpreted as imagined in #61731
Aside from this syntactic sugar, I'd expect the resulting types/values to behave just as regular struct types. In particular, we'd access the fields using .F0
(no special case for using a naked integer) and package reflect
would indicate that the type kind is reflect.Struct
.
(Side-note: using parentheses for a "tuple literal" is familiar from some other languages, but I expect it's probably ambiguous in Go. It's also unlike any other composite literal; perhaps something with braces would be better.)
With all of that said, I already have some reservations:
- As noted above, an infinite (or, at least, very large) set of systematically-constructed predeclared identifiers is probably without precedent in the language, although I'd be happy to be corrected on that. This is both a compiler implementation complexity hazard and a "teachability" hazard.
- Introducing a shorthand that removes the word "tuple" and doesn't resemble a struct will make it hard for an unfamiliar reader who has encountered a shorthand tuple type or literal to find out what it means through search. I might prefer something that has a searchable keyword in it, but introducing new keywords to the language is challenging.
- The above seems to imply that tupleN
... are named types rather than anonymous types. I must admit that I'm not familiar with how the compiler "thinks about" the predefined identifiers that represent unnamed types, but if possible it might be better to treat these as anonymous struct types despite them technically having names, similar to how int32
is not a "named type" despite it appearing to have a name. In particular, I'd expect that to mean that reflect.TypeOf(tuple2[string, int]{"", 0})
would be exactly equivalent to reflect.TypeOf(struct{F0 string, F1 int}{"", 0})
.
- I imagine this should incorporate something like #33080 to help heal the incoherence between the existing function argument/result "tuples" and this new kind of tuple, but I'm not sure what would be best for that.
Comment From: jimmyfrasche
I came up with a similar sketch with some different tradeoffs in https://github.com/golang/go/issues/33080#issuecomment-612543798
Comment From: ianlancetaylor
Per the discussion above, this proposal is similar to other, earlier proposals. It is also not clearly specified--what is the type of a tuple? And the emoji voting is not in favor. Therefore, this is a likely decline. Leaving open for three weeks for final comments.
Comment From: ianlancetaylor
No further comments.