-
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
Untyped consts should not be automatically type converted #41160
Comments
This is not correct, a and c are not ints, they are I typed integer constants. |
@davecheney I get that that's the the technicality of the Go spec (that I cited). However, if you ask Go for the type of those consts, it will say |
This is because int is the default type for an I typed numeric constant when it is assigned To a variable Those constants are not int, isn’t is the type of the value that is created when you pass those constants to fmt.Println |
Regardless of the technicalities of the Go spec on this point, the fact remains that this led to a real bug. A developer wrote |
Unfortunately this is not something we can change at this point. Just forbidding the conversions would break people's code (and break the Go1 compatibility promise). In order to change this behavior, we'd need a full proposal about how to handle existing code without breaking anyone. That's independent of whether we should make this change. I understand that the current behavior can cause bugs. But it is also convenient in many situations. Is there any way we can increase type safety without needing casts for code like below?
|
I understand it would be a breaking change, which is why I was hoping for at least go vet warning. (I believe there is some precedent for that.) With regards to your code sample, my immediate thought is that "conversion" of an untyped const to a compatible built-in type is okay, while anything else is flagged as a potential bug. const x = 10
type myInt int
func intFunc(y int) { ... }
func uintFunc(y uint) { ... }
func myIntFunc(z myInt) { ... }
func durationFunc(d time.Duration) { ... }
intFunc(x) // ok
uintFunc(x) // ok
myIntFunc(x) // flagged
durationFunc(x) // flagged |
Vet is not intended as a side-channel to introduce a language change. We have strict standards as to what is allowed to be added to vet, and I don't think this idea qualifies (because of the false positive problem). |
Can you elaborate on the false positive problem? In my experience, the reason people make typedefs like this is because there are semantics associated with the new type. Take |
Just grepping through the stdlib, there are cases like:
These uses are ok. Perhaps they are violating the abstraction, but they won't generate incorrect execution. Speaking of, why is this ok:
But presumably, we would want this to not be ok:
How do we distinguish the two? Or would you have to write:
|
Sure they may be technically correct, but my feeling is they should be "corrected" to I'm assuming your second question is about how go vet (or any automated tool) could tell the difference, yes? I don't know enough to say how it would work. const timeout = 60 * time.Second I think this is okay, and should continue to be allowed. const timeout = 60 + time.Second I agree, this shouldn't be okay. (I think this situation shows that it would be nice if Go supported operator overloading.) const timeout = time.Duration(60) * time.Second This is okay, but the typecast is unnecessary. Also, there is the matter of function typedefs, which in my experience ought to follow the same notions of implicit interface implementation. That is: type myFunc func()
func foo() { ... }
func bar(f myFunc) { ... }
bar(foo) // should still be okay even without a typecast So the more I think about, the more I think that if Go had (1) operator overloading and (2) proper enums, most of these type conversion bugs would go away. |
I agree that this code should be fixed to use the proper form. But Go made an explicit choice not to force people to change working code. That's the whole point of the Go 1 compatibility guarantee. We're not going to break user's code because we don't like their style.
RIght. If we're going to entertain this idea, we need an unambiguous rule about when an ideal constant can implicitly casted to a named type and when it can't. (For tools to use, certainly, but that's secondary. For humans to understand is primary.) |
Compare #20757. |
|
@ianlancetaylor Do you have an alternative proposal for avoiding these kinds of bugs with typedefs like If go vet cannot enforce this because in some cases it is more stylistic in nature, would golint be acceptable? |
@rittneje Run staticcheck (https://staticcheck.io/). It has checks for many things, including apparent misuses of |
Seems like Ian answered all your points here, and there doesn't seem to be anything else to do, so I'm closing this issue for now. |
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
Yes.
What operating system and processor architecture are you using (
go env
)?go env
OutputWhat did you do?
https://play.golang.org/p/iLPNLfxLl5e
What did you expect to see?
All five calls to
foo
should have been compiler errors due to an implicit conversion fromint
totime.Duration
.What did you see instead?
If the variable in question is a
const
, it is automatically type converted. In our case, this lead to a bug.I understand that this is as per the Go spec:
However, since this can easily lead to a bug, it would be nice if go vet at least warned about this situation.
The text was updated successfully, but these errors were encountered: