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

Check enum based on struct #33

Open
maratori opened this issue Dec 14, 2021 · 4 comments
Open

Check enum based on struct #33

maratori opened this issue Dec 14, 2021 · 4 comments

Comments

@maratori
Copy link
Contributor

There is alternative approach how to deal with enums in Go.
Example: https://github.com/ThreeDotsLabs/wild-workouts-go-ddd-example/blob/master/internal/trainer/domain/hour/availability.go
Article with motivation: https://threedots.tech/post/safer-enums-in-go/.

The idea is to use struct with private field and package level variables.
It would be great if exhaustive checks such enums as well, not only constants.

var (
	Available         = Availability{"available"}
	NotAvailable      = Availability{"not_available"}
	TrainingScheduled = Availability{"training_scheduled"}
)

var availabilityValues = []Availability{
	Available,
	NotAvailable,
	TrainingScheduled,
}

// Availability is enum.
//
// Using struct instead of `type Availability string` for enums allows us to ensure,
// that we have full control of what values are possible.
// With `type Availability string` you are able to create `Availability("i_can_put_anything_here")`
type Availability struct {
	a string
}

func NewAvailabilityFromString(availabilityStr string) (Availability, error) {
	for _, availability := range availabilityValues {
		if availability.String() == availabilityStr {
			return availability, nil
		}
	}
	return Availability{}, errors.Errorf("unknown '%s' availability", availabilityStr)
}

// Every type in Go have zero value. In that case it's `Availability{}`.
// It's always a good idea to check if provided value is not zero!
func (h Availability) IsZero() bool {
	return h == Availability{}
}

func (h Availability) String() string {
	return h.a
}
@nishanths
Copy link
Owner

nishanths commented Jan 26, 2022

This would be useful tooling generally. I'll have to think about whether I want to make it part of this program though. Primarily I want to think through the patterns/conventions that mark a given struct as an enum struct.

This might be interesting: https://github.com/BurntSushi/go-sumtype.

@nikolaydubina
Copy link

+1 to this. struct based enums are more robust in Go. would like to see this project to support it.

@nikolaydubina
Copy link

I would rather wrap struct enums over integer type. So it is very similar to current version.

@navijation
Copy link
Contributor

I think it would be good to be able to specify that any type could be an enum with a //exhaustive:enumerated tag, which should forbid any "instantiations" of the type outside the package's var block, + an equivalent regex configuration option for 3rd party types. What qualifies as an "instantiation" is a bit vague though if you want to deal with edge cases like pointer assignment.

Although perhaps that should be a different analyzer entirely or gated by a flag to avoid the extra cost for callers that don't want this feature.

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

4 participants