Live data from Hacker News

Compile-time safety for enumerations in Go

vladimir.varank.in

51–60 of 116 posts

Re: Compile-time safety for enumerations in Go

#51
post #45
post #34

Earlier quoted context omitted.

I'm not sure how that's comparable. Compile-time type safety is a boolean thing, you either have it or you don't. If you have it, then my example shouldn't compile. But it does compile, so you don't have it.

I think by insisting to view it only as a boolean thing is very limiting. By that measure, are the type safety hints of Python not really giving any type safety? Just give up and go home, as it were? :D I'm sympathetic to the points, I think. But I also don't have a problem with someone pushing for some type safety as long as you avoid actively trying to go against it.

> By that measure, are the type safety hints of Python not really giving any type safety?

If we're talking compile-time, then: yes, absolutely!

Type hinting doesn't provide type safety, because type safety isn't a spectrum.

Re: Compile-time safety for enumerations in Go

#52
post #8

I sometimes do this but idk if I would consider it 'elegant' The other 'gotcha' is that in switch statements the compiler can't tell whether you enumerated on all your cases as there is no true enum type so it's not uncommon to have a catch all default case that either returns an error or panics and hope you can catch it during tests if you missed a case. I just wish go had proper sum types.

This is an analyzer that will catch this: https://github.com/nishanths/exhaustive

I believe it's in golangci-lint.

Re: Compile-time safety for enumerations in Go

#53
post #27

Earlier quoted context omitted.

The type conversion is a red herring. He's just changing the value of a variable by referencing and dereferencing a pointer. In other words, he's not using a pointer conversion to change the value of `color.Red`, he's creating a new variable `c` and assigning `color.Red` to it, and then changing the value of the variable through the pointer and type conversion. But he doesn't even need to do the pointer/type conversi…

> But he doesn't even need to do the pointer/type conversion stuff, he could just do `c = Color("orange")` and call it a day. c = Color("orange") does not compile.

Ah, I misunderstood what type color.Red had. My mistake.

Re: Compile-time safety for enumerations in Go

#54
post #50

Earlier quoted context omitted.

No, you don't. If your module relies on compile time checks for validity, there's no reason for you to also include runtime checks. Other developers breaking your defined contract is not your responsibility, it's not even a bug.

> If your module relies on compile time checks for validity, ...then it's broken, because the Go compiler, factually, cannot (in general) check or enforce the validity of specific values. > there's no reason for you to also include runtime checks. Other developers breaking your defined contract is not your responsibility, it's not even a bug. It is absolutely the responsibility of the function func PrintColor(c Color…

Exactly. Someone could always connect to your program with a debugger and modify the instructions are being run, and that's why you need to regular runtime checks of the validity of your program text. If you want to handle people actively trying to undermine the assumptions your program is making, you can't leave out easy to replicate cases like 'gdb attach', obvious, non-accidental use of the type system, and other similar categories of issues.

What strategies do you use in your programs to ensure type safety in the event of debugging, mmap, and other mechanisms that can be used to subvert the memory layouts your compiler thinks it produced?

Re: Compile-time safety for enumerations in Go

#55
post #29
post #20

Earlier quoted context omitted.

I don't think the solution is trying to cover this. If a user does type conversion then usually they know what they are doing. It's like going out of the way. The solution is to just hide a type behind an interface to be explicit about it and to avoid the error that would have gone unnoticed otherwise.

The article is titled "Compile-time safety for enumerations in Go" but my example demonstrates that this is not the case.

You demonstrated that you can deliberately circumvent it.

Re: Compile-time safety for enumerations in Go

#56
post #54
post #50

Earlier quoted context omitted.

> If your module relies on compile time checks for validity, ...then it's broken, because the Go compiler, factually, cannot (in general) check or enforce the validity of specific values. > there's no reason for you to also include runtime checks. Other developers breaking your defined contract is not your responsibility, it's not even a bug. It is absolutely the responsibility of the function func PrintColor(c Color…

Exactly. Someone could always connect to your program with a debugger and modify the instructions are being run, and that's why you need to regular runtime checks of the validity of your program text. If you want to handle people actively trying to undermine the assumptions your program is making, you can't leave out easy to replicate cases like 'gdb attach', obvious, non-accidental use of the type system, and other…

That doesn't make any sense to me.

Most instructions are not atomic, so even if you had runtime checks something like a debugger could still inject invalid state in between your checks, making them ineffective.

If real-time code injection is your threat model, I don't see how runtime checks would get you anywhere.

Re: Compile-time safety for enumerations in Go

#58
Clever!

But what problem does this actually solve?

When I see a type alias of a string and enumerated variants then why would I pass in arbitrary strings?

There are _always_ ways to break assumptions. Putting arbitrary, complex guard rails at every call site doesn’t make a program magically better.

An API is primarily about affordances. We provide utility to the caller.

Re: Compile-time safety for enumerations in Go

#59
post #29
post #20

Earlier quoted context omitted.

I don't think the solution is trying to cover this. If a user does type conversion then usually they know what they are doing. It's like going out of the way. The solution is to just hide a type behind an interface to be explicit about it and to avoid the error that would have gone unnoticed otherwise.

The article is titled "Compile-time safety for enumerations in Go" but my example demonstrates that this is not the case.

It is the case under certain conditions.

Casting is by definition an escape hatch.

Re: Compile-time safety for enumerations in Go

#60
post #50

Earlier quoted context omitted.

No, you don't. If your module relies on compile time checks for validity, there's no reason for you to also include runtime checks. Other developers breaking your defined contract is not your responsibility, it's not even a bug.

> If your module relies on compile time checks for validity, ...then it's broken, because the Go compiler, factually, cannot (in general) check or enforce the validity of specific values. > there's no reason for you to also include runtime checks. Other developers breaking your defined contract is not your responsibility, it's not even a bug. It is absolutely the responsibility of the function func PrintColor(c Color…

It’s actually not and is one of those Java isms that have made its way into generalized software engineering.

If I write a function that takes Foo as an argument. I have a Foo implementation exposed elsewhere in my program. It is absolutely expected that I mean MY Foo, not your Foo. If you pass me your Foo, you will get unexpected results that are not a bug, not a side effect, not my responsibility. It’s yours, the caller, to adhere to the contract.

There are valid reasons to not adhere. To pass your own implementation. At that point, you are responsible for its use. Not me. If it adheres to MY Foo’s interface, you might get by, but it’s is not my responsibility to validate all permutations of unknown types to ensure you’re passing me mine. In go, it’s perfectly valid to return structs but accept interfaces as arguments so that you, the program author calling my api, can craft the correct program flow.

So please, leave that runtime type check reflection for Java and C# and the land of JS. We have no need for it here in machine code land.

Post reply on HN