Live data from Hacker News

From Python to Go to Rust: an opinionated journey (2018)

tech.allo-media.net

61–70 of 78 posts

Re: From Python to Go to Rust: an opinionated journey (2018)

#61
post #59
post #54

Earlier quoted context omitted.

I appreciate your work on Rust, I find it to be a very interesting language. > I think each of these three languages have made the correct choice, given their design ideals. I feel that's kind of side-stepping the issue though. The approach that golang took could match their design goals, but it doesn't mean that those goals aren't a bad idea in the first place.

For any set of correctness-improving primitives in a language, you can practically always come up with some disjoint set of additional primitives, and then make the argument that the lack of those additional primitives constitute "bad design". Sometimes you'll even be right (it's not clear to me in this case). But it will almost always be a boring argument.

In this case though, it's the addition of a "feature" that causes bugs, so lack of said feature will improve correctness.

Re: From Python to Go to Rust: an opinionated journey (2018)

#62
post #61
post #59

Earlier quoted context omitted.

For any set of correctness-improving primitives in a language, you can practically always come up with some disjoint set of additional primitives, and then make the argument that the lack of those additional primitives constitute "bad design". Sometimes you'll even be right (it's not clear to me in this case). But it will almost always be a boring argument.

In this case though, it's the addition of a "feature" that causes bugs, so lack of said feature will improve correctness.

Zeroing out uninitialized memory is a feature, one which significantly improves correctness over C/C++. Meanwhile, the scenario described in this blog post is shared by virtually every mainstream implementation language other than Rust.

Re: From Python to Go to Rust: an opinionated journey (2018)

#63

Earlier quoted context omitted.

It's a pretty big annoyance with Go though. I hate that all struct fields are optional.

there are times when a nil struct field is useful, like for trees and json. very easy to require struct fields by using a constructor

If it's useful, then the person creating the struct can explicitly set it to nil.

Re: From Python to Go to Rust: an opinionated journey (2018)

#64

Earlier quoted context omitted.

It's a pretty big annoyance with Go though. I hate that all struct fields are optional.

Isn't this something you could catch with a linter, if you wanted to?

Definitely but I'm not sure if there's a linter for this. If so, I'd love to use it.

Re: From Python to Go to Rust: an opinionated journey (2018)

#65

Earlier quoted context omitted.

It's a pretty big annoyance with Go though. I hate that all struct fields are optional.

FWIW, I never had that problem, but I also tend to use constructors for my structs.

When you use constructors you lose named arguments though.

One use-case where this is really painful: I like to encode sum types in Go using an interface with a private dummy method + structs that implement that. I then have a function "match" that takes one function per struct. It's nice to be able to pass these functions as a record since it gets ugly, but due to Go allowing omitted functions to be nil, if I add a case to the sum, I open myself up to NPEs everywhere. If Go had a warning for missing struct fields, it would tell me all the places I'd need to handle a new case.

Re: From Python to Go to Rust: an opinionated journey (2018)

#66
post #37
post #29

Earlier quoted context omitted.

Go has two mechanisms for initializing structs, name based and position based. type Sample struct { A int B int } can be initialized as Sample{A: 1, B: 2}, or Sample{1, 2}. The name-based method allows arbitrary elision of fields, which will be initialized to their zero value. This includes Sample{}, which will be interpreted as a name-based initialization that specified no fields. The position-based method requires…

The problem with using the positional method is that 1) It's much more difficult to read since you have to know the position of elements of the struct 2) You swap one compile time error for another: in the case you add and remove a field of the same type, it's entirely possible the program will compile fine if you use the positional initialization instead of the named one. #2 makes me think that the author would stil…

> It's much more difficult to read since you have to know the position of elements of the struct

At least the Go editor I use (GoLand by JetBrains, one of the more popular ones) will display the names of all the fields in positional initializers inline with the code (just as they would be in a named initializer), so it's pretty much the same readability-wise. There's a special color for these automatic labels that indicates they aren't actually part of the document.

> in the case you add and remove a field of the same type, it's entirely possible the program will compile fine

True although I think it's easier to work around this (by fixing the compile errors from removing the old field before adding the new one).

Re: From Python to Go to Rust: an opinionated journey (2018)

#67
post #29
post #6

> I compiled the code and … no error message. Everything went fine. But?! I just added a field to a struct, the compiler should say that my code is not good anymore because I’m not initializing the value where it should be! This is your big hangup with Go? You added a new field, didn’t use that field anywhere, and the compiler didn’t complain? I’ve heard a lot of valid criticisms of the language but this is a new one…

Go has two mechanisms for initializing structs, name based and position based. type Sample struct { A int B int } can be initialized as Sample{A: 1, B: 2}, or Sample{1, 2}. The name-based method allows arbitrary elision of fields, which will be initialized to their zero value. This includes Sample{}, which will be interpreted as a name-based initialization that specified no fields. The position-based method requires…

I agree, I use positional initializers pretty often to get behavior you describe. Not sure about VSCode but if you use GoLand it will even prefix the field names right in the editor, so there isn't really any readability difference.

One other reasonable alternative for OP in Go might be to simply use initialization functions (NewSample() or sample.InitWithX()) for certain structs. It's a bit more flexible with the ability to have multiple initializers and non-zero default field values (and of course also solves the issue of generating compile errors in the rest of the code when new fields/parameters are added).

Re: From Python to Go to Rust: an opinionated journey (2018)

#68
post #62
post #61

Earlier quoted context omitted.

In this case though, it's the addition of a "feature" that causes bugs, so lack of said feature will improve correctness.

Zeroing out uninitialized memory is a feature, one which significantly improves correctness over C/C++. Meanwhile, the scenario described in this blog post is shared by virtually every mainstream implementation language other than Rust.

I don't see it in Java or C# for instance. You have to explicitly opt into it by (1) declaring default (parameter-less constructors), and (2) exposing fields you want mutated via setters.

On the other hand, golang does not have the ability to prevent "default constructors", and the fact that it has no ability to make types file private further makes this an issue.

Re: From Python to Go to Rust: an opinionated journey (2018)

#69
post #68
post #62

Earlier quoted context omitted.

Zeroing out uninitialized memory is a feature, one which significantly improves correctness over C/C++. Meanwhile, the scenario described in this blog post is shared by virtually every mainstream implementation language other than Rust.

I don't see it in Java or C# for instance. You have to explicitly opt into it by (1) declaring default (parameter-less constructors), and (2) exposing fields you want mutated via setters. On the other hand, golang does not have the ability to prevent "default constructors", and the fact that it has no ability to make types file private further makes this an issue.

Java initializes variables to their zero values. If you want to hide Go struct members from other "files", you can do that trivially by putting them in subdirectories.

Re: From Python to Go to Rust: an opinionated journey (2018)

#70
post #29
post #6

> I compiled the code and … no error message. Everything went fine. But?! I just added a field to a struct, the compiler should say that my code is not good anymore because I’m not initializing the value where it should be! This is your big hangup with Go? You added a new field, didn’t use that field anywhere, and the compiler didn’t complain? I’ve heard a lot of valid criticisms of the language but this is a new one…

Go has two mechanisms for initializing structs, name based and position based. type Sample struct { A int B int } can be initialized as Sample{A: 1, B: 2}, or Sample{1, 2}. The name-based method allows arbitrary elision of fields, which will be initialized to their zero value. This includes Sample{}, which will be interpreted as a name-based initialization that specified no fields. The position-based method requires…

Initializing through explicit constructors e.g. `func NewSample(a, b int) Sample {...}` can also add a compile-time check. Of course the onus is once again on the developer to remember to use the `New` funcs instead of instantiating directly.

Edit: spelling

Post reply on HN