11 ms·
Function Currying in Go
- ThreeFx 7y agoCompared to other languages, I find Go's syntactic support for partial application and currying lacking, and every http.HandlerFunc I weep for the redundancy I create. I get that that is Go's design philosophy, but IMO a little syntactic sugar would be nice.
- Insanity 7y agoAuthor here! I'm pretty happy that I can use Go to do these things, but you are absolutely right that without the syntactic sugar it gets quite messy to read! Lambda expressions - sure you can do them - but it'd be nice if you also had the syntax we came to know from other langs. (->, =>)
- stunt 7y agoGO syntax is very regressive comparing to where we hopped programming languages should go. I believe GO success is partly because in recent years, we have many new specialized engineers that programming isn’t their main focus (DevOps, Data Scientists, SREs) and naturally they are looking for tooling with shorter learning curve. Also when you consider how many developers have a hard time to learn GIT after so many years, you realize why companies need something as simple as GO comparing to Rust, or Java comparing to Scala for instance.
- F-0X 7y ago>GO syntax is very regressive comparing to where we hopped programming languages should go. Speak for yourself maybe, but I appreciate Go's overall style. You also mention Rust and Scala in your post. If that is to be the future of language syntax, I should quit.
- minxomat 7y agoThe syntax being regressive is pretty objective. It's not a value judgement. It has it's pros and cons.
- shantly 7y agoI like that I can dive into pretty much any Go code and it won't be doing anything basic some way I'm not used to or can't very quickly figure out without having to look anything up. Kinda like Java in that regard, but even more so, plus way less verbose. I mean it's gotten better but take Javascript where just a few years ago fundamental branching & execution order and might be provided by some library and it wasn't always the same one (thinking especially of various competing promise libraries) or friggin' imports might look different. Or Rails where you might have a codebase come across your laptop that's in some version you haven't used recently and using a bunch of libraries you're not used to and now half the symbols in a given file aren't defined there or anywhere else that Grep can find and it's unclear where they even come from, so it's off to the docs for a bunch of abandoned gems to get any sense of what's even going on. Go mostly avoids that sort of deeply unproductive junk. It does achieve that by not providing certain things, plus static typing (thank god for TypeScript, finally some sanity). I'm OK with that. I don't use it as my daily driver but I'm never even a little sad to drop into or contribute to a Go codebase, and I don't need a huge margin of uncertainty on the question "how fast can you get up to speed with this?" for Go code, which I can't say of just about any other language, sight-unseen.
- spullara 7y agoGo is pretty verbose, especially error handling, vs modern Java code.
- mhd 7y agoI'm getting some serious Java 1.x flashbacks here, so just give it 20 years…
- pjmlp 7y agoAs early Java adopter, I find it ironic that Java is already considered a PhD language from Go users point of view.
- nine_k 7y agoIt took mere 8 years for Java to implement generics, though.
- apta 7y agogolang is older than that at this time. They deliberately ignored proven concepts in programming language design for some hand-wavy goal of "simplicity", making unsubstantiated claims about "programming in the large" and "scalabilty" along the way.
- nine_k 7y agoTo quote some other HN comments: "systems PHP", "If I need a well designed language, I have Rust. Go's sell for me is it's so naively simplistic it's actually useful when your team members are idiots". These are a bit harsh, but sort of hints on the target audience: people who have neither a lot of programming experience, nor a developed taste, but have practical problems to solve without shooting themselves in the foot.
- Insanity 7y agoThat seems unnecessarily harsh towards Go programmers in my opinion. Languages have different up and downsides and different areas where they shine. There's plenty of people with a lot of programming experience writing Go, and whose taste might just have diverged a bit from the "mainstream". :)
- aasasd 7y agoYou just name all variables with five characters max and save typing on that.
- jerf 7y ago"http.HandlerFunc I weep for the redundancy I create." Are you properly using the Template pattern, and creating middlewares that factor out repeated bits? There is some stuff that doesn't work for very well, but it does work for many things and it's easy to miss. (Go doesn't have many tools. You must learn to use the ones you have to the fullest. If you do, the remaining gaps are much, much smaller than commonly supposed.)
- atombender 7y agoMiddlewares force you to use a Go context to pass data, which has its own downsides. I personally much prefer passing data explicitly — through function composition and structs and so on — to contexts.
- jerf 7y agoSpecific "middleware libraries" may; the general concept does not. The general concept is just to wrap a decorator around an http.Handler with something else that implements http.Handler. You don't need any sort of specialized "middleware support"; all Go interfaces already support being decorated. I have found that there is a bit of a misconception in the Go community that there's something special about http.Handler and that you need lots of special code to deal with it. I've seen the misconception that "middleware" is something special and that you can only do it to http.Handlers a lot, but a "middleware" is just "a decorator applied to http.Handler". You can decorate any interface value the same way. There's also a misconception that "routers" are something special, like, they have their own type or something. But they aren't. They're just http.Handlers that can examine a request and figure out which other http.Handler to call. One thing I do a lot is wrap my top-level logger around the "router" that is the top level of my website; in one shot, you decorated the entire website. It's all just http.Handlers, there's no "real" distinction.
- atombender 7y agoRight, I was specifically referring to routers like Chi where you attach middlewares to a "mux". These don't rely on function composition, and so the only way to pass information onwards — loggers, sessions, and so on — is to use contexts. The community has a lot of nice middlewares that do things like basic auth, session management, cache headers, etc. If you use decorators and not middlewares, you'll have to write your own middleware code.
- edem 7y agoThe language is lacking in every other department as well, so it is not a surprise.
- wgx 7y agoOff-topic: I see 'medium.com' and I don't tap because I can't face the pop-ups and nag modal. Sad to think, at one time Medium used to be the cleanest reading experience.
- enriquto 7y agoThe site looks lean and clean without javascript.
- giongto35 7y agoThis post has more votes than medium's ...
- Elrac 7y agoMight be against the rules, but here's a "me too." I've been avoiding Medium even before they became so blatantly commercial. Forcefully urging me to create an account and log in just to read a bloody article? No thanks.
- gremlinsinc 7y agothe trick is open devtools click 'application' and click clear all site data. Then refresh, no nags etc...
- kasbah 7y agoI use the "Make Medium Readable Again" browser extension because of this. Firefox also has a reader view which I use on a lot of other sites. https://makemediumreadable.com https://makemediumreadable.com
- minxomat 7y agoI usually hate these kinds of comments but I have to: Please check out dev.to. It's a minimal, fast, developer focussed blogging platform. It's open source, and quite active.
- iikoolpp 7y agoIn 3 months time: Off-topic: I see 'dev.to' and I don't tap because I can't face the pop-ups and nag modal. Sad to think, at one time Medium used to be the cleanest reading experience.
- jtdev 7y agoCall me crazy, but I find the sub-optimal “takes a lot of parameters” approach to be more readable, maintainable, and junior dev-able. Don’t get me wrong, I see why that’s not ideal, but currying just seems immensely more complicated and harder to maintain, teach, etc... of course I’ve voided any chance of membership to the “clever programmer club” with this perspective, but I stopped caring about that long ago.
- fireflies_ 7y agoMe too. I can't imagine trying to maintain a project written like this so I'd still consider you a member of the "clever programmer club" in good standing. Ideas like this make sense when the language gives you good support for them like Haskell does: https://www.haskell.org/tutorial/functions.html https://www.haskell.org/tutorial/functions.html In languages like Go, you'll write much more "composable" software by sticking to what the language gives you instead of trying to force this in.
- cousin_it 7y agoI think even in Haskell, function composition is a bit of second class citizen compared to function application, e.g. "foo (bar value)" has fewer tokens than "(foo . bar) value". There are languages based on composition (concatenative) but few people use them.
- karmakaze 7y agoI remember working in a Go codebase and that was littered with functions that take functions returning funtions that take functions, etc. I couldn't imagine what compelled them to write this way. Now I can see that they just realized first-class functions, dependency injection, and maybe an article about currying. There was almost no way to follow the problem decomposition nor execution path as each aspect rather than being dealt with as encountered just got pushed into a more and more complicated function that eventually executed everything when given the input, an http request!
- weberc2 7y ago
- gizzlon 7y agoYou can do this, but should you? Solutions like this, more abstraction to avoid repetitive code, are usually much worse than the problem. > Though we notice we only greet for mornings and afternoons so always having to pass “Good morning” or “Good afternoon” becomes a bit annoying. Maybe? But one can do much much much worse than "a bit annoying" > It would be great if we could create an instance of our “greet” function with the first argument pinned down. No.
- iikoolpp 7y agoAh yes, the Go mantra. Make your code as dumb and long as possible.
- gizzlon 7y agoCompared to what? I used to do scripting languages and Go code is usually more verbose. Not much more verbose though. Think it's mostly the static typing. While keeping things short is a goal, it's not the only goal..
- dgb23 7y agoWriting dumb code is often a good thing. Dumb code still solves your problem and can be structured well to keep it readable and maintainable. I feel like code even should be dumb most of the time and only clever when needed. The hard part is to figure out when to be clever.
- qt-lmao 7y agoWrite clever code then dumb it down
- JyB 7y agoFound a “clever programmer club” member.
- tgv 7y agoI sort of agree. I had a project in which I wanted to use Go, but I ended up writing Emacs macros to repeat boiler plate code. That wasn't pleasant, and to me it meant that Go wasn't the most suitable language for that problem. That applies here too: if you find yourself writing too much boilerplate code in favor of an abstraction, try another language. If you want/have to continue in Go, look for another solution.
- H1Supreme 7y agoI usually create a struct once my parameter list goes past 3. Then, pass that in. Or, if applicable, create a method instead.
- Insanity 7y agoIn production code I do this too. The struct approach has various advantages (nice syntax, maintainable, shows the meaning of what you are passing, ..). I like functional programming hence the blogpost, and I like that I can do this in Go. There are places where you might want to do this but I'm not going to advocate doing this _every chance you get_. But hey, Go lets me write how I want and that's pretty cool!
- vips7L 7y agoIn Java we would use `String.format`. https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#format-java.lang.String-java.lang.Object...- https://docs.oracle.com/javase/8/docs/api/java/lang/String.h...
- Insanity 7y agoOh thanks :) I wasn't sure anymore about how I'd do it in Java so I wrote "a language that looks like Java". Took the easy way out instead of having to actually look it up. I'm going to leave it as it is though but good to know ;-)
- cozos 7y agoString.format is slow compared to normal string concatenation (i.e. "foo" + "bar")! Bit me once when using String.format in a hot path. https://stackoverflow.com/questions/513600/should-i-use-javas-string-format-if-performance-is-important https://stackoverflow.com/questions/513600/should-i-use-java...
- vips7L 7y agoThose benchmarks can't be accurate as they don't use JMH. Edit: i do believe you that + is faster, as it doesn't need to parse the format string, but you should still always do benchmarks with JMH or they won't be accurate.
- deleted 7y ago[deleted]
- eximius 7y agoI mean, is this even currying? Or just emulating currying? Without it being done automatically, it is an ergonomic loss, readability loss, etc.
- deleted 7y ago[deleted]
- contravariant 7y agoDon't confuse special syntax with the concept itself. Currying is merely an equivalence between functions of 2 parameters to functions of 1 parameters that return functions. Doing it explicitly is still currying all the same.
- kazinator 7y ago> Though we notice we only greet for mornings and afternoons so always having to pass “Good morning” or “Good afternoon” becomes a bit annoying. There are solutions for this specific example not involving currying, like making a simple convenience wrapper: func greet(greeting, name string) string { return fmt.Sprintf("%v %v", greeting, name) } func goodMorning(name string) string { return greet("Good Morning", name) } Or just binding "Good morning" to a variable like gm and using that in repeated calls to greet: greet(gm, "This Person"); greet(gm, "That Person"). That is still reasonably ergonomic, and avoids repeating the greeting string.
- kitd 7y agoThe point is about composability of functions though. Your example does it statically. Currying and partial application allows it to be done dynamically within the running program.
- deleted 7y ago[deleted]
- kazinator 7y agoActually my example is based on partial application involving anonymous functions. It's just hand compiled. I manually lifted the lambda to the top level, and de-anonymized it with a name. Then I realized that the only captured parameter had a binding to a string literal "Good Morning", so I propagated that literal into the closure body, eliminating the variable, and that variable's environment. It ended up looking static due to the static literal, basically.