Skip to content
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: Go2: automatically take address of pointer parameters (reference arg behavior) #33088

Closed
rcoreilly opened this issue Jul 12, 2019 · 5 comments
Labels
FrozenDueToAge LanguageChange Suggested changes to the Go language Proposal Proposal-FinalCommentPeriod v2 An incompatible library change
Milestone

Comments

@rcoreilly
Copy link

[Apologies if this is a dupe -- couldn't find it.]

This proposal is to automatically take the pointer address (i.e., apply the & operator) of any non-pointer parameters that are passed to function arguments declared as pointers. This would make the behavior for the rest of the arguments consistent with the behavior for the receiver arg in a method.

When calling a method that is declared with a pointer receiver, the compiler automatically takes the address of a non-pointer variable.

Likewise, it would be more consistent, and convenient, if the compiler also automatically took the address of non-pointer parameters passed to pointer args. This would effectively mimic the behavior of the reference type from C++, without introducing any new syntax, and would not affect the ability to compile existing Go1 code as it is just turning what is currently an error into a valid function call.

Example:

func (r *MyType) MyFunc(oth *OtherType) {
...
}
...
    a := MyType{}
    b := OtherType{}
    a.MyFunc(b)  // compiled as: a.MyFunc(&b)
...
@gopherbot gopherbot added this to the Proposal milestone Jul 12, 2019
@ianlancetaylor ianlancetaylor added v2 An incompatible library change LanguageChange Suggested changes to the Go language labels Jul 12, 2019
@ianlancetaylor
Copy link
Member

The disadvantage is that normally when writing F(x), I know for sure that x does not change (of course, if x is a slice or map, some elements of x might change, but x itself will not change). It's true that the receiver behaves differently, but that is a case that Go programmers know to be aware of. Making this change will make it harder to understand what happens when reading Go code.

Speaking only for myself, I think this would be a bad idea. When I personally write C++ code, I use pointers, and I use const references, but I never use non-const references. There are existing C++ style guides, such as the Google style guide, that make the same choice (https://google.github.io/styleguide/cppguide.html#Reference_Arguments) (I work at Google but I don't write C++ at Google). So this suggestion is trying to bring in a feature from C++ that a significant number of C++ programmers intentionally avoid. Simpler to not bring it in in the first place.

@rcoreilly
Copy link
Author

I understand and appreciate that perspective. However, just to push back a bit: given that Go does not have const, it is not possible to adopt that coding style. Adopting this change would actually enable greater semantic clarity about the arg usage (i.e., a "poor man's const"): use an explicit & for args that are modified, and don't add & for "const" non-modified args. Thus, the code reader could then easily tell which args are being modified and which are not. The code writer presumably knows the semantics of the function and can decorate accordingly.

This convention would obviously not be enforced by the compiler, but could be part of the standard style guide and enforced in code reviews etc.

@ianlancetaylor
Copy link
Member

The arguments given above (#33088 (comment)) seem valid. There does not seem to be strong support for this proposal, based on emoji votes and the lack of comments. Therefore, this is a likely decline.

Leaving open for four weeks for final comments.

-- for @golang/proposal-review

@rcoreilly
Copy link
Author

One last comment I guess: are there any better ideas out there for const-like decoration? Seems like all the other alternatives I've seen have been closed, but there is clearly some interest in having such a thing in general, and yet almost all of the proposals lead to the horrible const poisoning phenomenon..

So this is a way to obtain a small amount of const-like decoration, of exactly the sort @ianlancetaylor suggested for const-references vs. non-const pointers. Just to spell it out more explicitly with a lame example:

// CopyFromOther copies from other type into my type.
// src is not modified and should be passed using a reference
// dest is changed and should be passed using a pointer 
func CopyFromOther(dest *MyType, src *OtherType) {
    ...
}

func code() {
   var mt MyType
   ot := OtherType{Name: "source", ...}
   CopyFromOther(&mt, ot) // reading this, I know that mt is modified and ot is not
}

It would likely be possible for the compiler (or an optional vet-like tool, if too expensive to do on every compile) to trace down from the "const reference" call into the function to check if the arg was actually mistakenly modified, and issue a warning / error in that case. Thus, if someone uses a function with the expectation that the arg is const, then they can get a static error about this expectation being violated, which would catch bugs that would otherwise only be caught at runtime, and are hard to trace etc. And this avoids const poison because it is only about the usage, not the marking of the args themselves, so passing a non-reference (i.e., pointer) arg is not an error.

So, overall, this proposal seems like it could provide a minimalist, but effective way of marking and enforcing const expectations, without const poison, and it also makes the language overall more consistent in its treatment of receivers vs. other args, and would not break existing Go1 code.

@ianlancetaylor
Copy link
Member

Thanks for the additional comment, but it doesn't seem to change the overall thoughts above. Yes, it might be nice to address this general issue in some way, but this doesn't seem like the best way for Go.

@golang golang locked and limited conversation to collaborators Nov 4, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge LanguageChange Suggested changes to the Go language Proposal Proposal-FinalCommentPeriod v2 An incompatible library change
Projects
None yet
Development

No branches or pull requests

3 participants