-
Notifications
You must be signed in to change notification settings - Fork 17.8k
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 & as l-value operator #40708
Comments
Aside from saving one line, what would this allow go programmers to do that they cannot do today? |
The benefit I see is that it makes for a simpler mental model. Much like how there is interest to make You are not wrong that in the provided example it only saves one line, and you can always define more stack variables to solve a problem, but I think there is an elegance to direct assignment that is valuable. Also, I would ask why we allow |
Alternatively the type of s.URL could be changed to avoid having to add a new syntax. |
There are valid reasons one may not want to use pointers. That being said, there may also be an opportunity for the compiler to optimise |
I can’t see an argument for not changing the fields type to make the code read better. It can’t be for performance because if it was the copy from the dereferencing u will dominate. This just doesn’t feel like a change that would improve Go enough to pay for itself. I think there are more valuable changes that could be made given the extremely conservative stance to adding anything to the language. |
I assume from your example that the semantics of
is equal to
I don't like operators on the LHS that are really operations on the RHS. Having |
This comment has been minimized.
This comment has been minimized.
This seems like a very specific example of the fact that when a function returns more than one result we can't apply an operator directly to the result. For example, one could similarly imagine rewriting func F1() (int, error) { ... }
func F2() {
var (i, j int; err error)
i, err = F1()
j = -i
} as func F2() {
var (j int; err error)
-j, err = F1()
} That is, the same pattern arises for any unary operator. And in fact it arises for any binary operator if we use the What's special about the unary |
That is fair, I am game for adding other operators (with return values) as valid l-value operators. I just started with something that I saw and had an intuitive and readable solution. You can currently deref l-values, so why not address them too? If I understand your suggestion correctly, this would involve the following unary operators. I think everything makes intuitive sense and reads pretty well: var (i int; b bool; p *int; err error)
+i, err = strconv.Atoi("5") // 5, <nil>
-i, err = strconv.Atoi("5") // -5, <nil>
!b, err = strconv.ParseBool("true") // false, <nil>
^i, err = strconv.Atoi("5") // -6, <nil>
*p, err = strconv.Atoi("5")
&i = flag.Int("i", 0, "")
c<-, err = strconv.Atoi("5") The assignment operators have a bit of stutter to them: On the other side of the argument, since I fear @ianlancetaylor's comment was a straw man, if we are uncomfortable adding any more l-value operators, maybe we should consider removing the ones we have in some future Go2 release. Clearly they are not required, since we can just make more stack variables. |
I dont think we have any l-value operators, at least not in the sense of That is, because we are permitted to write |
To me having all unary operators also on the left side impairs readability as the operation on both left and right side need now be merged mentally to understand how the value of an expression assigned is computed. They might also be visually much further away the current examples. EDIT: I understood the example wrong... the below wont work for multiple returns
|
Interesting, so I cannot |
This comment has been minimized.
This comment has been minimized.
What would its address be? What would it mean to store a value at that address? |
I think I follow your confusion. Assignments currently place a value into a location. My suggestion is to unpack (dereference) a pointer into a location: // copy the value returned by F() into value p points to
*s.URL = F()
// shallow copy the pointer returned by F() into the temporary pointer of s.URL
&s.URL = F() I see how that could be unintuitive, if you read it as desugaring into: p := &s.URL
p = F()Because there is no way to desugar I assume
// s.URL unchanged But this is like saying that these are equivalent: *s.URL = F()
// and
v := *s.URL
v = F() As such there must be custom logic to unpack
Is it not reasonable to say that
|
Looking back at a different example we see that: var a uint
var b *uint
&a = b // store the value b points to into a
// is equal to
a = *b // get the value b points to and store it into a Where as: var a *uint
var b uint
a = &b // get the address of b and store it into a
// is not equal to
*a = b // store the value b into the location pointed to by a As I see this, in the second case we have one thing To me this makes sense and seems intuitive, since assignment is not equality, but maybe that is not a universal point of view. |
The nature of assignment statements in Go (and most imperative languages) is to store a value in a variable somewhere in memory. Given an arbitrary assignment statement
(Exception: map assignment logically and even internally works this way, though There's no "custom logic" to unpack
You're proposing to add uniquely new syntax and semantics for how Typically a multi-valued functions that return a pointer (i.e., the functions where this proposal are applicable to) is going to have a return signature like Notably, your initial example ( |
Based on the discussion above, this is a likely decline. Leaving open for four weeks for final comments. |
No further comments. |
background
Currently you can use the deref operator,
*
, to assign aT
to a*T
:However there is no way to deref a returned value:
description
I propose we allow the reference operator,
&
, to be applied to l-values:costs
This adds a new operator for l-values, but the
&
operator has a consistent value, so it seems intuitive. Currently, this can probably only be added to=
, since:=
does not support*
, see #30318.This should be backwards compatible with Go 1.
The text was updated successfully, but these errors were encountered: