← Back to context

Comment by dkarl

21 hours ago

> The issue is that it was a bit outdated in the choice of _which_ things to choose as the one Go way

I agree with this. I feel like Go was a very smart choice to create a new language to be easy and practical and have great tooling, and not to be experimental or super ambitious in any particular direction, only trusting established programming patterns. It's just weird that they missed some things that had been pretty well hashed out by 2009.

Map/filter/etc. are a perfect example. I remember around 2000 the average programmer thought map and filter were pointlessly weird and exotic. Why not use a for loop like a normal human? Ten years later the average programmer was like, for loops are hard to read and are perfect hiding places for bugs, I can't believe we used to use them even for simple things like map, filter, and foreach.

By 2010, even Java had decided that it needed to add its "stream API" and lambda functions, because no matter how awful they looked when bolted onto Java, it was still an improvement in clarity and simplicity.

Somehow Go missed this step forward the industry had taken and decided to double down on "for." Go's different flavors of for are a significant improvement over the C/C++/Java for loop, but I think it would have been more in line with the conservative, pragmatic philosophy of Go to adopt the proven solution that the industry was converging on.

Go Generics provides all of this. Prior to generics, you could have filter, map, reduce etc but you needed to implement them yourself once in a library/pkg and do it for each type.

After Go added generics in version 1.18, you can just import someone else's generic implementations of whatever of these functions you want and use them all throughout your code and never think about it. It's no longer a problem.

  • The language might permit it now, but it isn't designed for it. I think if the Go designers had intended for map, filter, et al to replace most for loops, they would have designed a more concise syntax for anonymous functions. Something more along the lines of:

        colors := items.Filter(_.age > 20).Map(_.color)
    

    Instead of

        colors := items.Filter(func(x Item){ return x.age > 20 }).Map(func(x Item){ return x.color })
    

    which as best as I can tell is how you'd express the same thing in Go if you had a container type with Map and Filter defined.