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: allow channel/map/type assertions in return (val, bool) #36955

Closed
seebs opened this issue Jan 31, 2020 · 11 comments
Closed

proposal: Go 2: allow channel/map/type assertions in return (val, bool) #36955

seebs opened this issue Jan 31, 2020 · 11 comments
Labels
Milestone

Comments

@seebs
Copy link
Contributor

seebs commented Jan 31, 2020

What version of Go are you using (go version)?

1.13

Does this issue reproduce with the latest release?

Yes.

What operating system and processor architecture are you using (go env)?

N/A

What did you do?

var x map[string]int
func foo(in string) (int, bool) {
  v, ok := x[in]
  return v, ok
}
func bar(in string) (int, bool) {
  return x[in]
}

What did you expect to see?

I don't know.

What did you see instead?

So, it seems to me that the special cases of channel receive, map lookup, and type assertion are unique in go in that they are optionally multivalued. But my intuition is that there are very few cases in go where you can write x, y := expr; return x, y but cannot write return expr, and I'm not sure there should be any. I don't think it's any more confusing to accept return x[n] both for a single return value of the map type, and for two where the second is a bool, than it is to have the existing map lookup syntax.

@ianlancetaylor ianlancetaylor changed the title allow channel/map/type assertions in return (val, bool). proposal: Go 2: allow channel/map/type assertions in return (val, bool) Feb 1, 2020
@gopherbot gopherbot added this to the Proposal milestone Feb 1, 2020
@ianlancetaylor ianlancetaylor added v2 A language change or incompatible library change LanguageChange labels Feb 1, 2020
@ianlancetaylor
Copy link
Contributor

The concern here is that in a big function, there may be one case of return t.(v), and changing the result parameters of the function may continue to compile although that return statement will now in some cases unexpectedly panic.

Separately, if we change this, it would seem that we should also change the case of passing a a map lookup, etc., to a function F(int, bool). But this again is subject to the same kind of problem.

@seebs
Copy link
Contributor Author

seebs commented Feb 1, 2020

... Ooh, interesting. I hadn't thought about how this would interact with changes in other parts of the interface. There's also an ambiguity this potentially creates:

fmt.Printf("%v, %t\n", m[k])
fmt.Printf("%v\n", m[k])

The optional-returns from these things are a weird special case. There's probably similar things that would come up with range except that they can't because it can only occur in for.

I think I'm now mostly convinced that, at least as-written, this would be a bad idea, but I feel like it's vaguely a flaw that there's no way to express the distinction except through assignment operators.

@jimmyfrasche
Copy link
Member

There could be a builtin to make the expansion explicit. It wouldn't be used often but it's always kind of annoying to hit this corner.

@seebs
Copy link
Contributor Author

seebs commented Feb 1, 2020

I wonder how much it would break to allow return on an assignment expression.

@seebs
Copy link
Contributor Author

seebs commented Feb 1, 2020

Okay, so, I'm not sure I want this, but just in case the idea appeals to someone: One alternative would be to allow some kind of expression that can show up in, say, a return, or as a parameter to a function taking (T, bool), and explicitly selects the two-value semantics. I've thought about this a bit, and I think there's syntaxes that would be vaguely comprehensible. Some of them are "safe" -- they cannot mean anything else right now. I can't think of one of those for type assertion yet.

return m[[k]]
return <--ch // i don't think you can ever <- a thing that takes unary - right now
return <=ch // this is not what <= means but in context it would always be a syntax error
return x.((T))

The vague intent of these is to go for "a thing that is like the single-value form, but with some visual component doubled".

But on looking at it... I feel like this is probably not enough of a benefit to justify the ugly syntax. But if this inspires someone else, go right ahead.

@jimmyfrasche
Copy link
Member

The nice thing about a builtin is that it's as explicit as a separate syntax without the need for any additional syntax. Let's say it's called both since I can't think of a better name. Then the examples are

return both(m[k])
return both(<-ch)
return both(x.(T))

and it could similarly be used in function calls like

f(both(m[k]))
f(both(<-ch))
f(both(x.(T)))

You could use it redundantly like v, ok := both(x.(T)) but that's easy enough to catch with a linter

@bcmills
Copy link
Contributor

bcmills commented Feb 3, 2020

@jimmyfrasche, if we had generics, then you could implement both quite easily as a generic function that accepts two arguments. (No need for a builtin!)

@jimmyfrasche
Copy link
Member

I could write the type signature but it wouldn't be of much use.

@ianlancetaylor
Copy link
Contributor

There is already a way to do this, using variable declarations. Since this issue doesn't come up all that often, any new syntax or predeclared function has to be clearly better and simpler than the existing way.

@ianlancetaylor
Copy link
Contributor

As discussed above, there is some ambiguity here. And this proposal does not have strong support based on emoji voting. For these reasons, this is a likely decline. Leaving open for four weeks for final comments.

@ianlancetaylor
Copy link
Contributor

No further comments, so closing.

@golang golang locked and limited conversation to collaborators Mar 17, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

5 participants