3 ms·
What I really missed was generic map-function-over-slice, which could be handled by adding a much narrower feature. If one graded possible Go point ex
by nemo1618 5y ago
What I really missed was generic map-function-over-slice, which could be
handled by adding a much narrower feature.
If one graded possible Go point extensions by a figure of merit in which the
numerator is "how much Python expressiveness this keeps" and the
denominator is "how simple and self-contained the Go feature would be",
I think this one would be top of list.
So: map as a functional builtin takes two arguments, one x = []T and a
second f = func(T)T. The expression map(x, f) yields a new slice in
which for each element of x, f(x) is appended.
I think this is an excellent way of evaluating new features, and it represents a real missed opportunity for Go to explore new PL territory. Instead, we're getting full-blown user-defined generics, which increases the "denominator" far, far more than it increases the "numerator."
- throwaway894345 5y agoI also came from Python (15 years of experience) to Go and I think newcomers to Go index too hard on terseness. The for-loop equivalent for a map over a list is more characters, but it's really straightforward and easily recognizable in the code. In the general case, I'm glad that Go doesn't try to explore new PL territory, optimizing instead for things that are known to improve developer productivity. None of this is to say that Go has no room for improvement--only that "terseness" is not high on the list of improvements I'd like to see (for example, I'd rather have sum types with exhaustive pattern matching).
- nemo1618 5y agoFor me, it's not a question of terseness -- it's more about communicating intent, and not polluting the scope with incidental variables. Everyone knows what map/filter/reduce do. When reading new code, seeing "map" is better than seeing a for loop: you don't have to think about the underlying iteration at all, you can skip directly to the essence of the transformation. As a side effect of this, when you do see a for loop, you can safely assume that something about the iteration is non-trivial: maybe the loop exits early, for example. I wrote a bit more about this here: https://twitter.com/lukechampine/status/1463715093733122054 https://twitter.com/lukechampine/status/1463715093733122054 btw, by "new PL territory" I mean "reifying a small set of container operations, without supporting user-defined generics," which to my knowledge is not a position taken by any mainstream language.
- throwaway894345 5y ago> For me, it's not a question of terseness -- it's more about communicating intent, and not polluting the scope with incidental variables. A mapping for loop doesn't pollute scope with incidental variables: results := make([]Result, len(input)) for i := range input { results[i] = callback(input[i]) } ^ This only adds `results` to scope, which is the same as `results := map(input, callback)`. In the for loop example, the loop variable `i` is scoped to the loop. Moreover, if you don't care about terseness, you can always pull this out into a well-named function or annotate it with a comment. > Everyone knows what map/filter/reduce do In isolation, but for complicated chains of map/filter/reduce (especially with error handling logic in languages which return errors rather than raising them as exceptions) it's much easier for me to read the corresponding for loop equivalent. Even my colleagues at a Python shop had limits on the complexity of list comprehensions beyond which point they were required to rewrite into a for loop because while packing that complexity into a single expression is elegant and clever, it's not particularly readable or easy to understand. I guess my view can be summarized as: for very simple cases, map/filter/reduce are a bit clearer, but for those same simple cases a for loop is still easily understood and a for loop's readability scales better with complexity.
- nemo1618 5y agoThat's exactly the view I express in the Twitter thread lol
- pcwalton 5y agoESR's proposal here is basically just another way of spelling Python list comprehensions or Perl 5 map (which is likewise a builtin, with special parsing rules). It's not "new PL territory" by any means.
- throwaway894345 5y agoI think the "new PL territory" was referring to a type-safe generic map builtin. Obviously Python and Perl don't have a concept of type safety. That said, I still wouldn't call that novel in the sense that a builtin version of a well-understood generic function doesn't seem like a feat of ingenuity.
- lucian1900 5y agoMost statically typed languages have a type safe generic map or it can be easily built. Just like with monomorphisation, Go just stubbornly rejects all PL research younger than 40.
- throwaway894345 5y ago> Most statically typed languages have a type safe generic map or it can be easily built. That's my point. > Just like with monomorphisation, Go just stubbornly rejects all PL research younger than 40. That's flamebait.
- preseinger 5y ago> a real missed opportunity for Go to explore new PL territory But Go was not intended to explore new PL territory. Is that not OK?
- nemo1618 5y agoI would argue that it is: it's explicitly a language designed "in the service of software engineering," which is something we're still figuring out how to do. It has implemented novel features that serve this end, and left out features that don't. PL design doesn't have to just be about dependent types and borrow checkers, after all.