-
Notifications
You must be signed in to change notification settings - Fork 18k
go/doc: treat function returning array as constructor #22856
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
Do you have any examples? We did not do arrays in the previous issue because noone could find a decent, real use case. |
I was wondering why that was. Maybe I missed something.
func NewPair() [2]T { return [2]T{..., ...} }
func RepeatT(func() T) <-chan T
… On Nov 23, 2017, at 1:04 AM, Daniel Martí ***@***.***> wrote:
Do you have any examples? We did not do arrays in the previous issue because noone could find a decent, real use case.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub, or mute the thread.
|
Those still seem like examples you came up with, not real examples from the standard library or well known packages. I think it's important that we base this on common practices. Otherwise, it would be hard to tell when to stop. For example, what about funcs that return a func returning T? And what if we combine some of these rules, and end up with a func like:
The reason that slices were added was because there were a few occurences in the standard library, so it was a clear win. I can't think of any such real cases involving arrays and channels off the top of my head, hence why I'm asking if you have any. |
As far as I know, there aren't any in the standard library. I don't know about golang.org/x or other well-known packages.
I hear what you're saying about pragmatism, and I agree that it can steer you right in a lot of cases. My concern is that consistency is important too. Things that intuitively seem alike should be alike. The pattern of Here are perhaps some better array examples:
versus
And perhaps some better channel examples:
versus
|
Arrays probably should have gone in with slices. I'm skeptical about functions returning channels (or maps) always being constructors. time.Tick returns a chan time.Time but it's not a time.Time constructor. proposal-review agrees with arrays but let's stop there. |
Accepted; CLs welcome for Go 1.11. |
Then please allow me one last shot at convincing you. :) Regarding maps, Regarding channels, it depends on how you define "constructor". Values are constructed in many ways from many sources, and not all of those sources are "constructors" as we mean here. IMO, it's simple and intuitive to define a constructor for a named type as above. You can even omit the "that you can get out" part, since it's common sense, leaving just So, the way I see it, Tick is a Time constructor. It actually does construct Times, which are given by the channel. Like a Time channel constructor, a Time slice constructor also constructs Times, which are given by the slice. I can understand if others don't see it that way, though. |
I think it's because the entire purpose of classifying constructors is to make it easier to figure out what functions to call in order to get new values of that type. The primary purpose of The case that I sometimes have problems with is that of a function that constructs multiple types at the same time. For example, SDL has a function, |
This assumes one only cares about the side effect of channel receiving, which isn’t always the case, and I would argue most of the time isn’t; most of the time, we use the received value. I don’t have the reference in front of me, but aren’t the Tick elements the current times? If so, those can be useful sometimes, and they’re newly constructed. I suspect there’s a hang-up about long-existing functions now being considered constructors because there’s a bias: for so long they weren’t, so we don’t think of them that way, and any change that changes that is therefore wrong. I suspect if they had been designated as constructors from the start, we would have been fine with that. So perhaps it’s more productive to discuss a hypothetical example, like my NewEventStream constructor above. Does anyone have a counterargument for why it isn’t an Event a constructor? |
Because it isn't for constructing I could also play devil's advocate and argue that it's again not really for 'constructing' |
(Edited) I forgot to respond to a part of @DeedleFake's second-to-last post:
One way to simplify the definition of "constructor" is that it only handles one named type (plus an optional error, or whatever). I wrote above, in part:
So it could be that SDL_CreateWindowAndRenderer isn't a constructor at all.
Some counterexamples: // The traditional slice constructor, for comparison.
func Registrations_slice_traditional() []Event {
var es = make([]Event, 10)
for i := 0; i < 10; i++ {
es[i] = getEvent()
}
return es
}
// Disproves: "[Slice] values are created right away and then returned."
func Registrations_slice_array() []Event {
var es [10]Event
go func() {
for i := 0; i < 10; i++ {
es[i] = getEvent() // Constructs events in itself after (probably) the return.
}
}()
return es[:]
}
// Disproves: "Because it isn't for constructing Events. [...] The Events are being constructed elsewhere, and then sent to you later."
func Registrations_chan_buffered() chan Event {
var es = make(chan Event, 10)
for i := 0; i < 10; i++ {
es <- getEvent() // Constructs events in itself before the return, not elsewhere.
}
return es
}
// Disproves: "Because it isn't for constructing Events. [...] The Events are being constructed elsewhere, and then sent to you later."
func Registrations_chan_unbuffered() chan Event {
var es = make(chan Event)
go func() {
for i := 0; i < 10; i++ {
es <- getEvent() // Constructs events in itself after the return, not elsewhere.
}
}()
return es
} The source of the Events is up to the constructor. It's an implementation detail that doesn't affect the meaning of the function type, which is the only thing we're looking at to determine what is a constructor. As seen in the Registrations_slice_array example above, even slice constructor results can come from elsewhere (as can pointer constructor results, for that matter), so by definition that property isn't necessary for constructors. Perhaps the functions listed for a type should just simply be any functions that handle only that type, not just functions we think of as "constructors". NewEventStream is definitely only about Event, and, as my Event |
Change https://golang.org/cl/85355 mentions this issue: |
Hey all, I was hunting around for little contributions I could make and came across this ticket. Funny enough, I wrote the original slices-of-T change (https://go-review.googlesource.com/c/go/+/54971/6). Since @rsc has accepted to add arrays of type T as constructors, I was able to quickly create the CL for it: https://go-review.googlesource.com/c/go/+/85355 I wasn't sure what to do with the test - since the old test was invalid, I renamed the test after this issue and removed the old test. |
We should consistently implement #18063 with all types parameterized by one type that make sense. The missing ones are array and receiving channel. This would give us:
Plus all the
*T
equivalents, obviously.The text was updated successfully, but these errors were encountered: