What does HackerNews think of go-sumtype?
A simple utility for running exhaustiveness checks on Go "sum types."
type Vehicle interface {
isVehicle()
}
type Car struct {}
func (c Car) isVehicle() {}
type Van struct {}
func (v Van) isVehicle() {}
func VehicleType(vehicle Vehicle) {
switch v := vehicle.(type) {
case Car:
fmt.Println("car")
case Van:
fmt.Println("van")
default:
fmt.Println("unknown vehicle")
}
This covers most, but not all, of the bases, in that you don't get exhaustiveness checking at compile time, unless you adjoin a linter to your compile process: https://github.com/BurntSushi/go-sumtypehttps://github.com/BurntSushi/go-sumtype is great, but a bit unwieldy. Language support would be much better.
Go's for loops can only iterate over builtin types: slices, maps, channels, etc. You can't produce a custom type that is to be iterated over.
Alternative 1a is to use Alternative 1 with https://github.com/BurntSushi/go-sumtype /plug
go-sumtype requires the interface to be sealed (which you're already doing) and one small annotation:
//go-sumtype:decl TheInterfaceName
Then you just run `go-sumtype` $ go-sumtype $(go list ./... | grep -v vendor)
and it will do exhaustiveness checks in any type switch in which `TheInterfaceName` participates. This will prevent the "For example, during a refactor a handler might be removed but a type that implements the interface is not." failure mode mentioned in the article.While the article identifies some operational issues (e.g. the reliance on HTTP/2), there are several considerable deficiencies with gRPC today, at least when using it with Go:
1. The JSON mapping (jsonpb.go) is clumsy at best, and by this I mean that it produces JSON that often doesn't look anything like how you'd hand-design your structures. "oneof" structs, for example, generate an additional level of indirection that you typically wouldn't have. Proto3's decision to forego Proto2's optional values (in Proto3 everything is optional) cause Go's zero value semantics to leak into gRPC [1]. (We had to fork jsonpb.go to fix some of these issues, but as far as I can tell, upstream is still very awkward.)
2. The Go code generator usually produces highly unidiomatic Go. "oneof" is yet again an offender here. The gogoprotobuf [2] project tries to fix some of go-grpc's deficiencies, but it's still not sufficient. Ideally you should be able to use the Proto structs directly, but our biggest gRPC project we basically gave up here, and decided to limit Proto usage to the server layer, with a translation layer in between that translates all the Proto structs to/from native structs. That keeps things clean, but it's pretty exhausting work, which lots of type switches (which are hampered by Go's lack of switch exhaustiveness checking; we use BurntSushi's go-sumtype [3] a lot, but I don't think it can work for Proto structs, as it requires that a struct also implements an interface).
3. Proto3 has very limited support for expressing "free-form" data. By this I mean if you need to express a Protobuf field that contains a structured set of data such as {"foo": {"bar": 42}}. For this, you have the extension google.protobuf.Value [4], which supports some basic primitives, but not all (no timestamps, for example) and cannot be used to serialize actual gRPC messages; you can't serialize {"foo": MyProtoMessage{...}}. Free-form structured data is important for systems that accept foreign data where the schema isn't known; for example, a system that indexes analytics data.
From what I can tell, though, Twirp doesn't "disrupt" gRPC as much as I'd like, since it appears to rely on the existing JSON mapping.
[1] https://github.com/gogo/protobuf/issues/218
[2] https://github.com/gogo/protobuf
[3] https://github.com/BurntSushi/go-sumtype
[4] https://developers.google.com/protocol-buffers/docs/referenc...
For example, consider a parser that matches on tokens. If you add a new token, the match should fail, because you want to guarantee, at compile-time, that every possible case is handled.
This is one reason that the lack of sum types in Go is so painful, to the point that someone wrote a special library for it [1].