5 ms·
I understand that in the latter case, what fields are being assigned is clearer (albeit the former case can also adopt a similar order-based strategy). What I
by barosl 11y ago
I understand that in the latter case, what fields are being assigned is clearer (albeit the former case can also adopt a similar order-based strategy).
What I disagree is the "zeroing out" part. I don't want 0 or empty string to be more "special" than ordinary values. Letting the compiler decide what values are suitable if I omit them can be a cause of potential bug.
- Vendan 11y agoExcept that the spec states that the 0 value is "more special". https://golang.org/ref/spec#The_zero_value https://golang.org/ref/spec#The_zero_value I personally like it this way, and it's better, imho, to have a "set everything not specified to 0" step rather then "leave whatever garbage was there"
- barosl 11y agoHuh, I didn't know Go has a concept of implicit default value. In that aspect, zeroing out in struct literals also makes sense. However I would say that while default zero is better than garbage value, failing to compile is even better than default zero. (e.g. the compiler refuses to compile `var i int` in the first place) But I guess this is a matter of preference.
- reality_czech 11y agoIf the code failed to compile unless you initialized all values, you could never add a field to an existing type without updating all cases where you were creating an instance. This would basically make refactoring impossible in most real-world Go projects. You could potentially solve this problem by forcing all object creation to be through special constructor functions (like Java and Scala do), but that is not the Go way of doing things.
- barosl 11y agoYup, I'm much in favor of using a constructor, or even a trait, if such a breakage can be problematic, because I believe types are part of an API (so they should have been opaque types in the beginning). But I now understand what an idiomatic Go way is.
- wz1000 11y agoThat's why you use specialized constructors.
- pcwalton 11y agoAll ML-like languages as well as Swift and Rust, force you to initialize all values in the struct. Adding new fields isn't a problem in practice, because most of the time structs that you wanted to add fields to had private fields already to begin with, so they're using a constructor. The nice thing about this approach, of course, is that they can omit all the complexity of "zero values" from the language.
- sagichmal 11y ago> What I disagree is the "zeroing out" part. I don't want > 0 or empty string to be more "special" than ordinary > values. Sentinel zero values have been part of Go since day 1, and leveraged to provide some very nice semantics. See e.g. bytes.Buffer. It's a fundamental and useful part of the language.
- coldtea 11y ago>Letting the compiler decide what values are suitable if I omit them can be a cause of potential bug. The alternative is not to let you omit them, or to nil them. Both worse.
- masklinn 11y agoBut nilling them is exactly what Go does no? It initialises every field to their default/zero. Preventing their omission seems markedly better than the alternative, if you want to allow partial initialisations you can provide a constructor function or an explicit defaults construction.
- tracker1 11y agoExcept that without implicit declaration, how do you bring constructor variance into check? For example, if you have an object/class that has a lot of options available, you would have to create a huge number of constructor functions, or other extensions to simply initialize an instance... As I'm more familiar with JS than golang, it seems to me, with the current method, I can do something like... var inst = new CustomObject(param1, param2, { option15: 'bar' ,... }); Where the first two parameters are required, but the last one can be a structure that represents available/optional options as a singular type... This would be much cleaner than supporting every variation of overloads as part of object construction. Let alone where a type can simply be used directly.
- pcwalton 11y agoIn Rust you usually use either method chaining (CustomObject::new(param1, param2).option15('bar')) or the struct update syntax (CustomObject { param1: param1, param2: param2, option15: 'bar', ..DEFAULT_CUSTOM_OBJECT }) for this. No extra complexity of "zero values" necessary (and the concept of a zero value would be incoherent in Rust anyway).
- tracker1 11y agoBut you have either the complexity of multiple closures, or complex mutability (side effects) with that strategy, depending on how you approach your implementation. In either case the outcome could be less than ideal, and have more chance of unexpected results. Is this... var obj = new CustomObject(...); ... obj.option15('bar'); The same as var obj = new CustomObject(...).option15('bar'); IE: does calling option15 create a new closure/space that is separate from the original object (more functional separation) or does it mutate the original object? I tend to prefer to limit mutations as much as possible in my code... it really just depends on your needs.