4 ms·
I think some people feel productive when they write out a big loop, but to me it’s wasted effort. I want to write col.filter(_.isReady).map(convertToX).any(_
by erik_seaberg 6y ago
I think some people feel productive when they write out a big loop, but to me it’s wasted effort. I want to write
col.filter(_.isReady).map(convertToX).any(_.color == BLUE)
and generate whatever fused loops make that work. I don’t want to write and review loop boilerplate by hand for the same reason that I don’t want to customize the stack frame layout when I call a function.
- nikon 6y agoIt really doesn't matter day to day once you're in the loop (cough). I agree, it's an ugly language on the face of it, but you get over that quickly. You come to appreciate the language as a whole. A bigger concern when I started out with Go was the imports/lack of versioning, and at the time the lack of official package manager.
- solidasparagus 6y agoI've never found it much more painful to write: for i, c in range col { if c.isReady && convertToX(c).color == "BLUE": return True } (which is not to say I don't miss the map/filter syntax - although I don't miss the bugs related to lazy execution in stuff like LINQ or Spark)
- erik_seaberg 6y agoThat’s actually pretty good. Most people would use three more lines to create a temporary and break after setting it, and three to nine more depending on how many steps require idiomatic Go error handling.
- andykx 6y agoWould most people actually do that? That example seems like pretty idiomatic Go. I imagine junior developers would write that.
- erik_seaberg 6y agoI would typically expect anyBlue := false for _, c in range col { ready, err := c.IsReady() if err != nil { return nil, fmt.Errorf("isReady failed: %v", err) } if !ready { continue } x, err := ConvertToX(c) if err != nil { return nil, fmt.Errorf("convertToX failed: %v", err) } color, err := x.GetColor() if err != nil { return nil, fmt.Errorf("getColor failed: %v", err) } if color == BLUE { anyBlue = true break } } which badly obscures what’s going on but demands no cleverness at all (except that some might forget the “break” and still get the right answer).
- tmerr 6y agoIf IsReady, ConvertToX, and GetColor can return errors then this isn't that far off. But then you're not making an apples to apples comparison. You would have to extend your functional example so that it also handles errors. Unless it already does, and I am missing something.
- erik_seaberg 6y agoWhat I wrote should be pretty close to valid Scala, which handles exceptions. I can imagine wanting to skip an isReady failure, which looks like col.filter(c => Try(c.isReady).getOrElse(false)) .map(convertToX).any(_.color == BLUE)
- tmerr 6y agoI see. Then in part the comparison is showing off exception handling, not FP. Rust is a good example of functional lang without exceptions (panics aside). In Rust there are many cases where I could use FP but opt not to because it can make error handling more awkward. For example to collect the result of a map operation to a vector, and if there is an error along the way you want to abort the entire operation. In functional this means collecting to a Result<Vec<T>>. Not sure if I'm just tired today but I can think of how to do it in 5 seconds with a loop. I suspect functional solution would be uglier.
- loopz 6y agoThis style makes developer forget the underlying costs though. It feels productive but it is harder to understand what work computer will do. Go is designed to be imperative, so is a complementary language.
- erik_seaberg 6y agoThat's true and we should embrace it. Higher-level languages should empower us. We should use profilers to measure actual bottlenecks when necessary, not make every potential bottleneck more painful to write and read forever.