-
Notifications
You must be signed in to change notification settings - Fork 18k
proposal: spec: Field expressions #59101
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
Comments
I think this might lead to confusion, as
Then But |
In a weird sort of way, this actually correlates with the way that method expressions and method values work, like it's filling in a missing slot in a type E struct { V string }
func (E) M() string {}
var s E
s.M // func() string
E.M // func(E) string
s.V // string
E.V // Syntax error. It is strange that it results in a function instead of a string, but I can't think of any other way to do it that would make sense. I wonder if #21498 would be a more obvious and general way of solving this: Edit: Whoops. I can do math. Really. |
Agree that this would be of limited value given |
Thanks for the suggestion. This is an interesting idea. There is only one operation you do on a method: you can call it. But there are (at least) two operations you can do on a field: you can retrieve the value and you can set the value. This proposal gives a special syntax for retrieving the value, but not for setting a value. In other words, this syntax is a getter, but there is no similar syntax for a setter. It doesn't seem right to have getters without setters. A method expression takes a method, which is something that is callable, and evaluates to a function, which is also something that is callable. So method expressions are similar to methods in some sense. But that is not true for these field expressions. This is similar to what @randall77 said earlier. |
This is quite simply worked around by defining the transform to always operate on pointers:
It does break some symmetry with method expressions though. I could imagine separate syntax for pointers, e.g. |
If the field expression returns a pointer then the nice |
It's an interesting proposal, and there is an analogy to method expressions. But it doesn't seem to quite work for setters, and it's unclear how often it is really useful in practice. Therefore, this is a likely decline. Leaving open for three weeks for final comments. |
Would you like new postfixes and explicit getter/setter?
( The postfixes introduces both getter and setter, not only one. Usage example: type S struct {
F FieldType
}
func MapS[T any](ss []S, f func(S)T) []T {
ret := make([]T, len(ss))
for i := range ss {
ret[i] = f(ss[i])
}
return ret
}
func ZipIntoS[T any](ss []*S, values []T, f func(*S, T)) {
for i := range ss {
f(ss[i], value[i])
}
}
var fields []string = MapS(
[]S{ {Field: "foo"}, {Field: "bar"}, {Field: "baz"} },
S.F?,
) // ==> []string{"foo", "bar", "baz"}
var sSlice = []*S{ {Field: "foo"}, {Field: "bar"}, {Field: "baz"} }
BroadcastS(
sSlice, []string{"one", "two", "three"},
(*S).F!,
)
sSlice // ==> []*S{ {Field: "one"}, {Field: "two"}, {Field: "three"} }
|
@youta-t That does not seem very Go-like to me. |
I think the mentioned issue can be solved if we use * operator to dereference it if its Age is pointer and we can use & operator to pass it as pointer. We can write:
|
To make it work on setters, I propose the following solution with one restriction.
|
Thanks, but we aren't going to do that. Nothing else in Go behaves that way. |
I respect the decision as a whole, but I'm curious about something. Is it similar to what the runtime does to implement map indexing operations? |
Ah, yes, it is introducing something new to avoid breaking existing codes. The weirdness is intended, to a certain degree. Considering Go-likeness, "Field Expression as Suppose that we have type Accessor[S, F any] interface {
Gettable[S, F]
Settable[S, F]
}
type Gettable[S, F any] interface {
// Get a field value typed F from S
Get(S)F
}
type Settable[S, F any] interface {
// Set a field typed F in S
Set(S, F)
} For Using this, we can write like next: type SomeStruct struct {
Field string
}
var sAccessor Accessor[SomeStruct, string] = SomeStruct.Field
var _ func(S)F = sAccessor.Get // = func(s S) string { return s.Field }
var _ func(S, F) = sAccessor.Set // = func(s S, f string) { s.Field = f }, but may have no effect.
var pAccessor Accessor[*SomeStruct, string] = (*SomeStruct).Field
var _ func(*S)F = pAccessor.Get // = func(s *S) string { return s.Field }
var _ func(*S, F) = pAccessor.Set // = func(s *S, f string) { s.Field = f }
var fields []string = MapS(
[]SomeStruct{ {Field: "foo"}, {Field: "bar"}, {Field: "baz"} },
SomeStruct.Field.Get,
) // ==> []string{"foo", "bar", "baz"}
var sSlice = []*SomeStruct{ {Field: "foo"}, {Field: "bar"}, {Field: "baz"} }
BroadcastS(
sSlice, []string{"one", "two", "three"},
(*SomeStruct).Field.Set,
)
sSlice // ==> []*S{ {Field: "one"}, {Field: "two"}, {Field: "three"} }
It is a bit (or 3 bytes) longer than postfixes, but concise enough for me. |
I'm not sure I understand the question. Map index expressions are like variable references; they act differently depend on whether they are on the left or right hand side of |
I agree with Ian, this isn't really needed, and would be a maintenance burden. just write a callback. |
There was further discussion, but no change in consensus. Closing. |
Go has a concise notation to derive a function from a method, https://go.dev/ref/spec#Method_expressions, i.e. we have notional desugarings of the form
The proposal is to allow the same for fields:
This seems a simple and backward-compatible extension to the spec (the above forms are currently rejected). Compilation is likely slightly more complicated than for methods, as it would require emitting and deduplicating synthetic getters, but seems not unreasonable.
The use-case is code that is parameterized by the structure of the data it works on, which has become much more plausible with the introduction of generics. For example, given:
We can replace
with the more readable
The text was updated successfully, but these errors were encountered: