-
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: add type constraints like reference only, assign before use #23968
Comments
Related to #23764. Frankly, right now, this is too vague. I think I understand the problem you are describing. But for a proposal to be useful, we need some kind of solution. You may want to consider adding a user experience report to https://golang.org/wiki/ExperienceReports. |
@ianlancetaylor I agree, it's too vague and all over the place. I just wanted to get out for discussion. Maybe something useful would come out of it or it turns out I'm asking for something ridiculous. Sorry if it's a dup. I tried searching but didn't find anything. #23764 sounds a lot like what I'm proposing. At least in regards to reference only part. |
Nit: To 'pass by reference' has no well agreed-upon meaning in Go because the language specification does not define it. It's just to 'pass a pointer'. |
@cznic didn't know that. What I mean by that is what channels, for example, already do. You can't pass them by value. So they're protected from kind of error I described. I would like to allow that functionality for any user-define type. |
Everything in Go is passed by value. It's the only way available. (Just like in C modulo array decay.) |
@cznic specification doesn't say it but we all understand what I mean by that. Maps, slices, channels, functions - they're all reference-only types. And that means that passing them as arguments will pass that specific instance. Not make a copy of an opaque struct that underlies the type. |
For example, slice is a small, 3-word structure and is always passed by value in the same way like an PS: Wrt 'specification doesn't say it but we all understand what I mean by that.' and previous 'no well agreed-upon meaning in Go': Q.E.D. |
It's easy enough to make a value non-copyable:
(That is from https://golang.org/src/os/types.go#L16.)
You can take its length and read from it. That can be quite useful. For example, a map might be seldom modified, so you want to lazily allocate it.
Too much magic for Go. Also, what do you do for something like
|
What if you're in the same package with
Slices have even more magic in them. Ether way, that was just a though. My main concern is with type restrictions. |
See also #21538 (comment) and #21538 (comment). |
Adding some sort of restrictions on how types can be used would certainly be useful. But this proposal only suggests one specific restriction, and not even the most commonly suggested one (which is some version of the C |
I know the title might be confusing. I have a hard time formulating this proposal (if you can even call it that) but want to get out here as I think it's important to consider. May be somebody will be able to write it out better if it is indeed something important.
Recently I stumbled upon a question on stackoverflow that described a bug caused by
sync.WaitGroup
being passed by value. As you can imagine, it caused a bug becauseWaitGroup
contains state and should only be passed by reference. And that made me remember that I also made that kind of error in the past. But it's not limited to wait group and I want to make it more general.In Go values can be passed by value or by reference. Some internal types are explicitly passed by reference. Some types have useful zero value, some require you to allocate them before use. All of this might come with experience but every now and then it still bites me. Like, for example, maps. Nil is zero value for maps but you can't actually use it like that. You have to allocate it. That doesn't match, say, slices which also has nil as zero value but you can pass nil slice to
append
and it will happily accept it. Doesn't seem to be a reason why maps are like that on the surface.What I'm trying to say by this is types require certain rules on how you should use them. These rules are not enforced and can be easily broken which leads to runtime panics or even hard to debug errors like in the case with wait group. Languages like Java and C# have no problem because everything is passed by reference. Internal Go types like maps and channels already doing that. So there is a need for that.
What I propose is to extend language to be able to specify these rules explicitly. I understand that vetting might solve this but I insist on solving this on a language level to benefit all user types, not a limited subset of what vet implements. I also strongly believe that this should produce compile time error and not be a part of a separate tool that may or may not be executed. What the actual syntax might look like is not important as I don't have a fully written out proposal. But you can imagine something like this:
What this would do is to force all variables of this type to be references. Dereferencing is disallowed. Embedding is allowed but enclosing type would probably be required to also be reference only. Method receivers reference only. Any violation would result in a compile time error.
Zero values may warrant a separate proposal but it kinda fits into this general proposal to specify rules on how to use types. In this case it should be possible to specify whether zero value is actually usable or you're required to allocate (assign) variable before use.
The goal here is to produce compile time error saying that you're trying to use a variable before assignment. So if you write
var m map[int]int
and try to insert something into it compiler would detect that and produce compile time error. The same goes for any user type. It's probably impossible to catch all cases as value may come and go from any place in the program but it would catch obvious errors.Or, alternatively, this could be limited only to maps so that trying to insert a value into a nil map would not panic but allocate map for you implicitly. But that's definitely a different proposal.
The text was updated successfully, but these errors were encountered: