If you are serializing this data a lot, then having ints vs strings is a significant advantage.
Again, it depends on your use case. If you don't care about serialization size, then I agree, it's extra effort that you may not need.
Even in this era of fast computers and preposterously large storage, one sometimes hits a situation where the way to get the improvements you need is to start number-representing your strings.
And yes, you may not start with ints, but you could easily add code for the marshal/unmarshal later on to convert those strings to ints for serialization purposes. And it wouldn't require a change to any of your other code, not to mention that if you stored these values in a database already you don't need to perform a migration either.
A {
Field1: field1,
Field2, field2,
}
Now adding a new field to A would require ensuring that all code paths initialize Field3, otherwise you're going to have silent errors at runtime. This has been solved ages ago in Java and C# and similar languages by means of constructors.You are correct that every situation where the struct in Go is initialized "bare" would need to be addressed if a field is added, but Go considers this a feature, not a bug (and, conversely, considers "bare initialization" of structs at dozens of places in your code to be bad practice if that struct could ever grow new fields). If you're bare-initializing structs, you're comfortable using them in a "loosey-goosey" context where zero-initialized fields are permitted (or, better, useful... https://www.youtube.com/watch?v=PAAkCSZUG1c&t=6m25s). In Go, the issue of required structure is addressed by wrapping the struct in an interface and then providing a function in the package that can create an instance of the interface. Used in that way, you get something very similar to a Java class (though Go doesn't force you into the "everything is a class" paradigm that Java demands).
I see this dismissive philosophy in golang a lot (I'm not saying you're doing it, mind you). The entire language is full of arbitrariness. I've seen enums being dismissed by the golang team just because, without providing any meaningful arguments. Same with how nullability was not addressed in the language, contrary to how proper modern languages have tacked the issue. The excuse? "that's how the underlying machine operates". Quite meaningless and dismissive really.
Time and time again, it's been shown that the goal is to have a simplistic (not simple) language that also makes it easy to write the compiler for. This breaks down at larger scales because reality is complicated.
I will trade - unhappily - ADTs for value types, automatic memory management, some language-level concurrency support, a compiler that builds our largest project in under two minutes, and a community large enough I can spend my time training new hires on fundamentals and business problems and not tool onboarding.
Code generation is always the last resort.
Where I work we are a go house, and the number of tools I've seen in our pre-commit configurations and in our development environment setup scripts is pretty intense. So is the number of questions around said tooling. There's a lot more friction than I'd expect. I can't even use lack of experience as an excuse for these questions because they're really talented people. Some of them have worked on the product for years, and have literally moulded the product's tooling into what it is today.
// pill.go
package painkiller
//go:generate stringer -type=Pill
type Pill int
const (
Placebo Pill = iota
Aspirin
Ibuprofen
Paracetamol
Acetaminophen = Paracetamol
)
Then running `go generate` will yield: $ cat pill_string.go
// Code generated by "stringer -type=Pill"; DO NOT EDIT.
package painkiller
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[Placebo-0]
_ = x[Aspirin-1]
_ = x[Ibuprofen-2]
_ = x[Paracetamol-3]
}
const _Pill_name = "PlaceboAspirinIbuprofenParacetamol"
var _Pill_index = [...]uint8{0, 7, 14, 23, 34}
func (i Pill) String() string {
if i < 0 || i >= Pill(len(_Pill_index)-1) {
return "Pill(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _Pill_name[_Pill_index[i]:_Pill_index[i+1]]
}
Note: indentation is messing up because of Hacker News, so ignore the indentation.Book
Genre
BookToGenre
GenreToGenre