Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> Contrary to the author's claim, I would expect both to fail to compile.

I wouldn't - the first example is undefined (is 123 Bar or Qux? I guess technically it should be Bar as without quotes it's an int... but it's not unusual for int's to be cast into strings on assignment) and I would expect it to fail. The second example explicitly states which variable is being assigned.

edit: Thinking more about it, I guess it could go either way, but it's just one of those things that once you do it once you know it.



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.


Except that the spec states that the 0 value is "more special".

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"


Huh, 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.


If 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.


Yup, 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.


All 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.


That's why you use specialized constructors.


    > 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.


>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.


But 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.


Except 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.


In 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).


But 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.


There is neither mutability nor multiple closures involved in the record update syntax.




Consider applying for YC's Fall 2026 batch! Applications are open till July 27.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: