Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: Go 2: add tuple type #61920

Closed
leaxoy opened this issue Aug 10, 2023 · 9 comments
Closed

proposal: Go 2: add tuple type #61920

leaxoy opened this issue Aug 10, 2023 · 9 comments
Labels
LanguageChange Suggested changes to the Go language Proposal Proposal-FinalCommentPeriod v2 An incompatible library change
Milestone

Comments

@leaxoy
Copy link

leaxoy commented Aug 10, 2023

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 ...

@gopherbot gopherbot added this to the Proposal milestone Aug 10, 2023
@zephyrtronium
Copy link
Contributor

Maybe aside from syntax, this is #32941. Per #32941 (comment):

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 a struct. That suggests that tuple doesn't add much to the language. So let's think about what tuple does add, and it would take to make that work with struct.

@apparentlymart
Copy link

apparentlymart commented Aug 10, 2023

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:

    Foo(struct { a int, b string }{ 4, "hello" })
  2. 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.

  3. 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.

@jimmyfrasche
Copy link
Member

#33080 wasn't about tuple types per se but it ended up talking about them a lot

@apparentlymart
Copy link

apparentlymart commented Aug 10, 2023

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.

@seankhliao
Copy link
Member

see also #12854 #35304

@seankhliao seankhliao added LanguageChange Suggested changes to the Go language v2 An incompatible library change labels Aug 10, 2023
@seankhliao seankhliao modified the milestones: Proposal, Go2 Aug 10, 2023
@seankhliao seankhliao changed the title proposal: add Tuple type proposal: Go 2: add Tuple type Aug 10, 2023
@seankhliao seankhliao changed the title proposal: Go 2: add Tuple type proposal: Go 2: add tuple type Aug 10, 2023
@apparentlymart
Copy link

apparentlymart commented Aug 12, 2023

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 🤷‍♂️) 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.:

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 proposal: spec: allow conversion between return types and structs #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.

@jimmyfrasche
Copy link
Member

I came up with a similar sketch with some different tradeoffs in #33080 (comment)

@ianlancetaylor
Copy link
Member

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.

@ianlancetaylor
Copy link
Member

No further comments.

@ianlancetaylor ianlancetaylor closed this as not planned Won't fix, can't repro, duplicate, stale Oct 4, 2023
@gabyhelp gabyhelp mentioned this issue Jun 13, 2024
@ianlancetaylor ianlancetaylor modified the milestones: Go2, Proposal Aug 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
LanguageChange Suggested changes to the Go language Proposal Proposal-FinalCommentPeriod v2 An incompatible library change
Projects
None yet
Development

No branches or pull requests

7 participants