go version)?1.13
Yes.
go env)?N/A
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]
}
I don't know.
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.
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.
... 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.
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.
I wonder how much it would break to allow return on an assignment expression.
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.
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
@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!)
I could write the type signature but it wouldn't be of much use.
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.
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.
No further comments, so closing.
Most helpful comment
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.