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

Setting to allow zero-values for structs #89

Closed
mitar opened this issue Jan 3, 2024 · 14 comments
Closed

Setting to allow zero-values for structs #89

mitar opened this issue Jan 3, 2024 · 14 comments

Comments

@mitar
Copy link

mitar commented Jan 3, 2024

In my code I often have return foobar{}, errors.New("some error") to return an empty struct when there is an error. Currently linter complains about that.

I can go around that by doing return *new(foobar), errors.New("some error") but that is too verbose for me.

So I wonder, could there be a setting to allow foobar{} and not complain about it? So if you initialize without any field, then nothing happens. If you add any field, then linter requires to add all of them.

@mitar
Copy link
Author

mitar commented Jan 3, 2024

Another example I have in my code is unsafe.Sizeof(unix.RawSockaddrUnix{}) when calling raw syscalls.

@navijation
Copy link
Contributor

@mitar I think the return foobar{}, errors.New("some error") case is already handled here. Do you have a reproduction?

That said, I agree with the general utility of ignoring empty struct literals in general. It comes in handy in many situations. e.g. I have a pattern of namespacing constructors using SomeStruct{}.New() instead of NewSomeStruct which exhaustruct complains about. Usually, people are not "forgetting" to fill out fields when they write down empty struct literals. There's almost always a legitimate reason.

@JakeCapra
Copy link

@navijation For me, the returnContainsNonNilError check throws things off. Sometimes I return a bool to indicate ok. And other times I return a struct that implements the error interface. In both these situations, the linter complains.

@mitar
Copy link
Author

mitar commented Jan 12, 2024

Do you have a reproduction?

I found this example in one of my libraries.

@navijation
Copy link
Contributor

It seems the linter requires the function to return something with exact type error, instead of anything that implements error.

I'm inclined to believe that the linter should never complain about empty struct literals in return values for the reason @JakeCapra mentioned. That said, one workaround would be to add a named return value e.g. out T and always return out. I find that nicer than repeating the type name.

@JakeCapra
Copy link

@navijation Any progress or update on this?

@xobotyi
Copy link
Collaborator

xobotyi commented Mar 4, 2024

Not yet - there is extra hard task on supporting comment directives on structures rather on field tags (tags will remain)
This one is kinds simple but yet a bit annoying - it requires to perform manual duck-typing that structu implements error interface. as for now it only allows zero-values for returns with exact error type.

As i am pretty tight on time now - anyone willing is free to come up with PR.
Basically new code have to be added to https://github.com/GaijinEntertainment/go-exhaustruct/blob/master/analyzer/analyzer.go#L197 in order to detect error interface compliance

@navijation
Copy link
Contributor

@xobotyi there is a semantic ambiguity here for this "return nil of type which implements error":

  1. (less common) some structs implement the error interface via value receiver, so there is no way to return a non-nil error
  2. (more common) a nil struct can still implement the error interface; returning (error)(nil) is not the same as (*MyError)(nil)

Namely, for case 2, consider this example

package main

import "fmt"

type SomeError struct{}

func (*SomeError) Error() string {
	return "There was an error"
}

func returnsSomeError() *SomeError {
	return nil
}

func main() {
	var err error = returnsSomeError()
	fmt.Printf("err is nil: %t\n", err == nil)
}

A bigger problem is that the zero value of a struct has many valid use case where developers might not want to subject it to exhaustive enforcement. Perhaps a better solution is to ignore enforcement on one of the following categorizations (maybe based on an analyzer config):

  1. all empty struct literals
  2. empty struct literals returned from a function
  3. empty struct literals returned from a function that returns multiple return values

I'm not sure which makes the most sense; I'm inclined to believe either 1 or 2.

@ruslanSorokin
Copy link
Contributor

ruslanSorokin commented May 8, 2024

Hi, there is a PR #102 which I think is pretty related to what you mentioned here earlier. It does not address cases where you return custom error from function whose return type is the custom error itself, but it does eliminate false positives when you return a custom error on the position of the error interface.

@xobotyi
Copy link
Collaborator

xobotyi commented May 20, 2024

@navijation imo the way it shoul be done - the one it is done already, but with support for detection of custom error types.

Therefore it can be detmined as allow empty structures in case return statement contain non-zero error

@xobotyi
Copy link
Collaborator

xobotyi commented May 23, 2024

Closing as #102 being merged.
Feel free to reopen in case made solution does not fit your purpose.

@xobotyi xobotyi closed this as completed May 23, 2024
@mitar
Copy link
Author

mitar commented May 23, 2024

Thanks!

@JakeCapra
Copy link

@xobotyi Any idea when this will be released?

@xobotyi
Copy link
Collaborator

xobotyi commented May 23, 2024

I will release minor version in the evening, but have no idea about release plan of golangci-lint

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants