4 ms·
> What I really missed was generic map-function-over-slice Me too, and mapping a map, a channel, etc. With generics, things will be easier, we can have iterato
by kubb 5y ago
> What I really missed was generic map-function-over-slice
Me too, and mapping a map, a channel, etc. With generics, things will be easier, we can have iterators, even lazy iterators, but there will still be no type inference in lambdas for arguments and return values and no easy currying, so things will still be awkward, but better.
> Keyword arguments
You can kind of do that by passing a struct as an argument, and represent the optionalness by having a pointer in the struct. That's still awkward, you can't easily make a pointer to an integer or string literal, you need a separate helper function for each primitive type. Overall it could be nicer.
> Annoying limitations on const
I think the Go constants are good, the fact that you can perform calculations on them in compile time also. But I wish there was some way to express immutability (and non-nilability) in the language. Programs are simpler with less moving parts.
> 14KLOC -> 21KLOC
That's to be expected, Go could be nicer if it was more concise, obviously that's a hard thing to balance, because you can end up with too obscure code, I just wish that there were some small improvements from time to time.
> Absence of sum/discriminated-union types
Yeah, I refer to it as Algebraic Data Types, where you can for example have your tree type to be a Node with children or a Leaf with value. And a function can accept a Tree that can be one of these. IIRC, the Go people claim that you can do kind of something like this with interfaces, but it's not very nice to use interfaces in this way and has some drawbacks.
> Catchable exceptions require silly contortions
I don't like exceptions, they disrupt the flow of the program - any function call could "return early", so you need to be always careful and account for that possibility. In C++ this was solved with RAAI, and it was a source of so many bugs that some companies just disallow exceptions internally.
> Aesthetic doubt
Yeah, it's there, some things in Go just come out ugly.
> Absence of iterators
Yes. Hopefully generics will enable implementing them.
- autarch 5y ago> You can kind of do that by passing a struct as an argument, and represent the optionalness by having a pointer in the struct. That's still awkward, you can't easily make a pointer to an integer or string literal, you need a separate helper function for each primitive type. Overall it could be nicer. I think using a builder is a better option in Go if you have more than 2-3 arguments. > Yeah, I refer to it as Algebraic Data Types, where you can for example have your tree type to be a Node with children or a Leaf with value. And a function can accept a Tree that can be one of these. IIRC, the Go people claim that you can do kind of something like this with interfaces, but it's not very nice to use interfaces in this way and has some drawbacks. Except you can't really do this with interfaces. If you need to get back to the concrete implementation of the interface, there's no way to know what all possible implementations might be. This is especially true since any type can implement an interface, not just the types you create initially. So someone else could implement `Tree` and you would not know to account for that in your function that accepts the `Tree` interface. I don't think there's any substitute for proper sum types in Go.
- kubb 5y ago> I think using a builder is a better option in Go if you have more than 2-3 arguments. But then you need to write all the setters, and something that was supposed to be simple, a function, becomes a whole contraption with a bunch of auxiliary code. Personally I would avoid that, and I definitely wouldn't make it a rule of thumb to use builders in every function with more than 2-3 arguments (maybe you meant something else).
- autarch 5y ago> But then you need to write all the setters, and something that was supposed to be simple, a function, becomes a whole contraption with a bunch of auxiliary code. Personally I would avoid that, and I definitely wouldn't make it a rule of thumb to use builders in every function with more than 2-3 arguments (maybe you meant something else). Yeah, it's tedious, but that's Go for you ;) Rust has the same issue, but there are macros libraries that will create the builder for you based on the struct definition, so it's _very_ trivial to create these builders. You could do the same with codegen for Go, but this always feels much worse to me than using macros for a number of reasons like having to install a separate tool, checking in generated files, making people run `go generate` after some (but not all) changes, etc.
- kubb 5y ago> Except you can't really do this with interfaces Apparently they decided that it would be too confusing to have variant types alongside interfaces for some reason, and they claim that interfaces handle a lot of the use cases of variants: https://go.dev/doc/faq#variant_types https://go.dev/doc/faq#variant_types
- autarch 5y agoYeah, "for some reason" is a good summary of many Go decisions. Rust has both (traits are somewhat like interfaces) and I don't feel like it's too painful, though using the trait type in function signatures is a lot more involved than in Go, and I still don't fully understand all the nuances. But the complexity isn't because of any overlap between traits and sum types.