5 ms·
This compiles: type Test int const ( T1 Test = 0 T2 = 1 ) func TestSomething(t Test) {} ... TestSomething(17) So this isn't a g
by amw-zero 5y ago
This compiles:
type Test int
const (
T1 Test = 0
T2 = 1
)
func TestSomething(t Test) {}
...
TestSomething(17)
So this isn't a good suggestion, because you can easily pass any int value and will not get a compiler error. You may as well be using strings at that point.
- donatj 5y agoFwiw a literal 17 in a function call, let alone anywhere outside an equation or constant definition is a code smell that should never make it past review. I see your point however.
- amw-zero 5y agoDepending on code review instead of a static type system does not scale. Look at all of the memory safety security vulnerabilities that are solved by "simply making sure to manage memory correctly." Also: variableDefinedInAFarAwayModule := 17 ... TestSomething(variableDefinedInAFarAwayModule) It's not always as clear as a constant value being passed to an incorrect type.
- donatj 5y agoI don't understand your example here, that's not going to compile. variableDefinedInAFarAwayModule is definitionally type int and will not be cast. It is also unpublished, so you couldn't be using it for a faraway module? Your 17 in the previous example has it's typed determined at compile time which is why it can be a problem. see: https://go.dev/play/p/jEdAhKDeLy6 https://go.dev/play/p/jEdAhKDeLy6
- amw-zero 5y agoAh thank you. That's slightly better then.
- EdiX 5y agoThis will not compile because the type of the variable is int not Test.
- schrodinger 5y agoYour point is valid, but the Go philosophy depends on you following conventions to have reliable code. This is true all over the place, e.g. you can easily ignore errors. Other languages take a stricter approach, and maybe that's better. Not defending (although I like Go), but it's really more a language philosophy than a singular defect. As the other commenter noted, this should fail code review and you should be using the provided constants, and it should be clear to you. And if you disagree (which again is totally valid), you should use a stricter language—there's plenty out there!
- mkdirp 5y agoI generally tend to use enumer[0] to generate some boilerplate code that can help with addressing this, e.g. the below would compile, but would error at runtime. There are probably linters out there that could catch this. With Go, linters are generally pretty good at catching this kind of stuff. package main import "fmt" type Test int const ( T1 Test = 0 T2 = 1 ) func main() { t, err := TestString("T1") if err != nil { panic(err) } TestSomething(t) } func TestSomething(t Test) { fmt.Println(t.String()) } Having said that, it seems weird to have to mimic enums, as opposed to actually having it. Doesn't feel like it would add much complexity, if at all. [0] https://github.com/dmarkham/enumer https://github.com/dmarkham/enumer
- rplnt 5y agoI mean, that's a pretty common usage of enums, isn't it? TestSomething(T1 & T2)
- morelisp 5y agoAnd this is the big, probably irreconcilable, difference in culture between the sum-typers and the compiler-assisted-named-valuers....