Higher-order functions in Go
eli.thegreenplace.net
eli.thegreenplace.net
The Rust support for closures is more pleasant than that of C but the innate `Fn`/`FnMut`/`FnOnce` dichotomy makes things more complicated.
[1] https://en.wikipedia.org/wiki/Funarg_problem#Upwards_funarg_...
struct {
fn foo() { /**/ }
}.foo
If you want closures that capture values, you just need to define the appropriate struct. I'm pretty sure with proper use of comptime reflection and custom allocators you can build pretty performant and ergonomic closures (albeit with a lot less memory and type safety of course).1) A lot of channels, because Python coders wanted iterators. (This got so bad I've seen memos circulated about channels not being allowed to cross public API boundaries.) 2) A lot of interfaces, because of Java
I am really happy about the recent trend towards a more functional style in the language, it's so much closer to what I think the authors intended the language to look like.
There is no such trend, at least not from the Go maintainers' side. Trying to write Haskell in Go is just as misguided and futile as trying to write Java in Go.
> in the language, it's so much closer to what I think the authors intended the language to look like.
I don't think so. The wanted it to be imperative like C or Pascal/Modula/Oberon, otherwise they would have started the design with ML or Lisp instead of C.
It is a lot closer in the sense that it is less indirected and simpler. The Go team have circulated style guidance to groups I was part of about how to properly structure public APIs, and for example functional callbacks are nowadays preferred over channels.
I completely agree that Go is not designed to be Haskell, and I personally cringe every time I see a library of map/reduce/filter functions. I still prefer this over the older sins of stuff like ITreeIterator.
When I say "functional style" I don't mean lambda calculus. I mean more recent libraries don't tend to return interface-typed values as much or use channels as iterators.
Go's the first kind of functional language. But so is almost everything else, even Java, now.
Back in the day, we talked about programming paradigms and whether or not a language supported them; we didn’t usually label languages by paradigm unless there was a fairly tight association of the paradigm with the language.
If performance suffers, it is up to the language to implement proper inlining and fusion.
> Higher-order functions improve readability, maintainability and correctness
Perhaps correctness, but readability and its close relation, maintainability, well that's another question. I think it depends partly on the person (I'm not very good at reading code) and very definitely on the quality of the written code. I have seen some very, very horrible functional code. Simply declaring that it is more readable doesn't fly.
Back to correctness: well, functional code tends to be shorter than non-functional code, and it's a known fact that the number of bugs seems to be a constant per the lines of code (or at least that's the accepted wisdom, let's go with it) so is the lower number of bugs in functional code directly proportional to its reduced size, or is there something extra work? If it's directly proportional to the reduced size, then you often can do a heck of a lot with procedural code to reduce its size as well, usually by simply defining extra procedures/functions instead of copy/pasting code (which is a disease that functional code can very definitely suffer from also!)
> If performance suffers, it is up to the language to implement proper inlining and fusion
And in the meantime you lose sales, your competitors do better and start eating your market share – if you were running a company how would that make you feel? You have to be realistic.
Anyway, I do appreciate that you weren't trolling and weren't dismissive of my post, so I've upvoted your response.
If you need a loop to work around a poor optimizer, at least use a preprocessor to generate it. Devs are expensive.
Do you have example code? I am now really curious, but don't know what to google.
[0] https://dave.cheney.net/2014/10/17/functional-options-for-fr...
(Go is still plenty fast with it)
You should preen less in your comments.
"An unfused map-filter chain is a performance disaster waiting to happen."
Could you share your experience with that perfromance disaster here?
It is not. Your program might still hit acceptable speed targets, but you're taking enormous absolute perf hits for extremely questionable gains.
The linked comment was about an implementation of partition with the specific problem of allocating too many slices in the opinion of the author. It was not about lo in general, did not help or shared any performance numbers E.g. for a size of a usual lists of <50 elements with filter() or the use case of three chunks, that people use when writing web applications (which I do, I don't write a database in Go - something the author could have found out my asking instead of assuming).
The problem with your comments isn't the context for what you're doing, it's the "40y, scaled and sold" bullshit. That's bragging, not an argument nor context. Or as a senior colleague used to remind me, "shipping is easy if you're willing to ship shit." I'm not here to discuss shipping.
What a nasty comment.