Go 1.27 Interactive Tour
171–180 of 219 posts
Re: Go 1.27 Interactive Tour
#172Earlier quoted context omitted.
It's hard to avoid, because (naming aside) the cognitive load is caused by higher order functions, which are hard avoid without causing massive code duplication. I understand the desire to keep things concrete and avoid high level abstractions, but it's a decision not to automate stuff that can easily be automated. It runs counter to the basic instincts and purpose of our field/industry. That's why it never sticks.
Honestly, I’ve written some applications that, on paper, should be the perfect candidate for generics. And yet I can still count on one hand the number of times generics have saved me from massive code duplication. Most of the time generics might be useful, I’ve ended up needing reflection too anyway. And at that point, I’m really no better off for generics.
The thing is that one use case is so essential, so foundational, that we really can’t just skip it. You need generic containers, for ergonomics and performance. I mean, compare C qsort to C++ std::sort.
The languages that “get around” generics, like PHP, include god containers in the runtime. The language I’m designing is also that way, I’d like to avoid generics preferably forever.
But there’s a tradeoff there. God containers are very flexible, and we’ve seen the ramifications of untyped PHP arrays.
Re: Go 1.27 Interactive Tour
#173"The best way to teach something new is to compare it to something the audience already understands." Could someone take the example, reduce it to a non-generic version for two types I DO understand, then show that with the new feature I can collapse them into the Box/Map example in the doc? I have 10+ years of Go experience and I can't make heads or tails of "(b Box[T]) Map[U any](f func(T) U) Box[U]"
If you instantiate it with concrete types, does "(b IntBox) Map(f func(int) string) StringBox" make more sense? You have a collection (in this case Box) containing values of type T, a function that maps values of type T to type U, and if you apply that function to all elements in that collection you get a collection of type U.
Re: Go 1.27 Interactive Tour
#174Earlier quoted context omitted.
If you instantiate it with concrete types, does "(b IntBox) Map(f func(int) string) StringBox" make more sense? You have a collection (in this case Box) containing values of type T, a function that maps values of type T to type U, and if you apply that function to all elements in that collection you get a collection of type U.
Only they are not using a collection and therefore "Map" was a confusing choice for the method name (maybe "To" would have been a better name?).
Re: Go 1.27 Interactive Tour
#175Earlier quoted context omitted.
If you instantiate it with concrete types, does "(b IntBox) Map(f func(int) string) StringBox" make more sense? You have a collection (in this case Box) containing values of type T, a function that maps values of type T to type U, and if you apply that function to all elements in that collection you get a collection of type U.
Only they are not using a collection and therefore "Map" was a confusing choice for the method name (maybe "To" would have been a better name?).
Now, the verb "map" is the traditional name for this operator, but I agree it sounds confusing when the noun "map" is also a collection type. C# and SQL call this Select, if that helps.
Re: Go 1.27 Interactive Tour
#176Earlier quoted context omitted.
Only they are not using a collection and therefore "Map" was a confusing choice for the method name (maybe "To" would have been a better name?).
Is that really the confusing part? If you had a general collection interface, say Mapper, a Box (i.e. a singleton set) could implement it just as well as a List or a Tree.
Re: Go 1.27 Interactive Tour
#177Earlier quoted context omitted.
Yeah a few years ago there was a lot of buzz around it, but ultimately when presenting and polling all the options to the community, the general consensus was that existing error handling was actually fine. The other options added complexity and were harder to read.
[flagged]
Moreover, the "obvious" solution, i.e. treating (T,error) returns the same as Result, does not actually work. The problem is that (T,error) behaves like a product type while Result is a sum type and yes, some Go code does (ab)use this. In particular, the io.Reader.Read method in the standard library allows implementers to return (n>0,io.EOF), which has no equivalent Result representation. Many people consider this allowance to be a mistake, but it's too late to change it.
Re: Go 1.27 Interactive Tour
#178Earlier quoted context omitted.
Is that really the confusing part? If you had a general collection interface, say Mapper, a Box (i.e. a singleton set) could implement it just as well as a List or a Tree.
I realize that mathematically speaking a singleton set is still a set, but as a programmer who is used to map operations in other mainstream languages, I was expecting some kind of loop in the implementation. It took a few page faults in my brain to realize what's going on.
Re: Go 1.27 Interactive Tour
#179llm generated
Re: Go 1.27 Interactive Tour
#180Earlier quoted context omitted.
I understand that this is true for a lot of application code. It's not true for library authors though, and every language needs libraries.
I’ve written a lot of libraries too. The problem is generics only solve a very small part of the equation: compile time checks for composite types. But to use composite types in anything non-trivial in Go, you then need reflection. Which is slow. And if you then need reflection, you’re already passing interface types anyway plus you’re back to having to handle type-handling errors in the runtime. So if you’re writing…
The Go language itself is never its strength but it has a good runtime, wonderful standard library and tooling. People never picked Go for being an amazing language, but rather for these other things.