-
Notifications
You must be signed in to change notification settings - Fork 41
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
Add option to allow cuddling of var declaration and an expression that uses that variable's reference #83
Comments
I think I get your concern perfectly fine! 😄 This is interesting, I guess I'm not used ot see config := Configuration{}
err := json.Unmarshal(body, &config) As you might have seen in the other issue, the rule is described here. It's configurable to allow cuddling of var declarations like this: var foo = 1
var bar = 2 Maybe an alternative would be to extend the usage of the The only thing I think would be hard would be to handle these cases, but maybe that's not needed? // Actually only one declaration
var (
config Configuration
)
err := json.Unmarshal(body, &config) // "Separated" declarations
var (
err error
config Configuration
)
err = json.Unmarshal(body, &config) // Although this should be seen as
// err := errors.New()
// config := Configuration{}
// json.Unmarshal(...)
// Which isn't allowed either
var (
err error
config Configuration
)
err = json.Unmarshal(body, &config) |
Hah, I never tried this with Anyway, it's more complicated...with this code: config := Configuration{}
err := json.Unmarshal(body, &config)
if err != nil {
... we get On the other hand, this is valid: var (
config Configuration
err = json.Unmarshal(body, &config)
)
if err != nil {
... And I get why it's valid, but...it doesn't seem right that one is and the other is not :D Oh man I don't envy you managing this tool ... 😂 But yeah, as you wrote
I think that makes sense, I personally don't differentiate between these two as they are basically different syntax for the same thing. I would be cautious with throwing in a plain assignment |
The reason for someResult := getResult()
if someResult > 0 {
// ...
}
someList := []int{4, 8, 15, 16, 23, 42}
for _, v := range someList {
// ...
}
This to me is one of the most obvious places to use the config := Configuration{}
if err := json.Unmarshal(body, &config); err != nil {
return nil, err
}
return &config, nil
If that's valid that is what I would call a feature (a.k.a. a bug I won't admit is there by accident!). I guess it's just a coincidence that the last assignment is Regarding managing this, I don't plan to support all end every combination of every feature. I want this to help me and others to write code that looks the same while making it readable by grouping code by usage. I want to find a way where I can be strict with some basic ideas (such as never cuddle blocks, just don't...) but avoid false positives. I don't mind if something I wouldn't write is allowed, however I don't want to give warnings on things that doesn't work 100% consistent. Since bundling this in
Well, yes and no. As long as But to sum it up, a lot of times the I don't see any major issues having the current var x = 1
var y = 1 And var x = 1
if x > 0 {
// ...
} And essentially just making it equivalent with the |
Except for the name |
I think |
Yeah we can work on the name, I also see I had a type, was trying to write You are right about them all being declarations, they're just no all explicit. They are however not all assignments. At least this is what I've been taught, but I guess it's possible that I'm wrong here.
Although I found this interesting so I did some testing and compiled these three programs with package pkg
func x() int {
x := 0
return x
} package pkg
func x() int {
var x int = 0
return x
} package pkg
func x() int {
var x int
return x
} And yeah, it's obvious that since the declaration only version (the last one) isn't a pointer and thus cannot be nil, this will all result in the same behaviour: PCDATA $0, $0
PCDATA $1, $0
MOVQ $0, "".~r0+8(SP)
RET So I guess this shows that it would be even more reasonable to treat |
I think you are kinda wrong about And it looks like you confirmed that with the compiler :) And yeah, of course, linter is for us, humans :) But in that case, I think it's pretty agreeable that both syntaxes are the same, on both the compiler level and on the eyes :) |
Hehe, I think we are saying the same thing with different words and I agree with you! All of them are partly declaration but not all of them are assignment. You can omit the type with They are two separate types in the AST from Go's own standard library. See DeclStmt which is the node after the You are right about the latter also being a declaration (which is required to assign/initiate the the value). From the documentation:
So an assign statement is partly a declaration but a declaration does not always include an assignment. This is the reason for the different behaviour, combined with the fact that the AST which the linter is based on returns different types for them. And also why I avoid to use them interchangeably. TL;DR: We agree with each other on what the syntaxes do and if they look the same to the eye or not boils down to opinions. We also agree on that it would be a good feature for the linter to be able to treat Oh, and PRs are welcome since I don't know when I will find the time to implement this! |
I never looked at Go AST before, but from what you wrote it seems they just named them wrong :D But yeah, we agree to agree 😂 I will definitely give it a look, but since I have no experience with Go linters/Go AST, I can't promise anything :) Although I wrote huge number of PHP sniff rules for phpcs, so I guess that should be pretty similar ... we'll see :) |
Not sure if this applies here but another similar case is when you need to declare an error variable because the return from a function is going to an exising variable, but error has not been defined func someFunc(in *someThing) error {
var err error
in, err = someOtherFunc()
if err != nil {
return err
}
} The assignment cannot use That is just a very basic example. The issue with that is either the var err error and the call to the function can be cuddled or the function call and the error handling, but not both. |
Merged in golangci/golangci-lint#1750, will be available in next release. |
So how can one allow the code example from above:
I still get "only one cuddle assignment allowed before if statement" error. |
You can't, but that's not a part of how cuddling and usage of Alternative allowed ways could be f.ex. var config Configuration
err := json.Unmarshal(body, &config)
if err != nil {
... or var config Configuration
if err := json.Unmarshal(body, &config); err != nil {
... |
Sorry, I'm not sure how to describe it better, so here goes an example:
Another that comes to my mind:
When there is an empty line in between these two statements seem really disconnected, while I consider them more or less a single statement, which isn't possible due Go "limitations".
The text was updated successfully, but these errors were encountered: