5 ms·
Every FP advocate I know comes from an imperative/OOP background… None of them are juniors. None of the “FP skeptics” (or people parroting an obvious variant of
by epgui 4y ago
Every FP advocate I know comes from an imperative/OOP background… None of them are juniors. None of the “FP skeptics” (or people parroting an obvious variant of uninformative “right tool for the job”) I know come from an FP background.
People only seem to convert one way and not the other. And is it really a surprise that the vast majority of people resist change / doing things differently?
- JackFr 4y agoI was 3 years hardcore Scala, but recently went back to Java for a role. I didn't really find returning to Java to be an encumbrance at all, and really enjoyed how productive Spring Boot made me. I still love Scala and if you don't fight it and use it long enough, the crazy sounding FP/category theory stuff starts to come up naturally and seem very comprehensible. My takeaway is always avoid known bad practices, but otherwise to cut with the grain. Write Java like Java, JavaScript like JavaScript and Scala like Scala.
- mrkeen 4y agoHear, hear. When I program, I like to use: { functions, types } When FP gets bolted onto a mainstream language after the fact, you get to program with: { classes, mutability, side-effects, nulls, functions, types } Then the FP skeptics think it's too complicated, and just want to go back to: { classes, mutability, side-effects, nulls }
- epgui 4y agoWhy not just use COBOL and Gotos while we’re at it? It was “the right tool for the job” for decades until the OOP religion took over! /in_jest
- mrkeen 4y agoSure /s. But seriously I dislike the notion that FP is somehow a successor to OOP, like you have to keep piling abstractions onto OOP until it becomes FP! If you do it that way, you end up with map() implementations like: public final <R> Stream<R> map(final Function<? super P_OUT, ? extends R> mapper) { Objects.requireNonNull(mapper); return new StatelessOp<P_OUT, R>(this, StreamShape.REFERENCE, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) { return new Sink.ChainedReference<P_OUT, R>(sink) { public void accept(P_OUT u) { this.downstream.accept(mapper.apply(u)); } }; } }; } Ain't nobody got time to read that. Step back from OOP before putting in the FP and you can get map() looking like: map _ [] = [] map f (x:xs) = f x : map f xs
- epgui 4y agoPersonally I do see FP as a “successor” to OOP, but not in a strictly constructive or chronological sense. Building FP functionality with classes sounds just as fun as building java classes with assembly.
- _old_dude_ 4y agoThe problem of the Java code above is that it tries to serve many masters, one of them being the JIT, i.e. the code is written that way so the JIT can fully inline the whole code. The first "final", the "StatelessOp", the "StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT", the "int flags" are all here because of performance.
- teh64 4y agoWell your second example relies for speed and efficiency on Haskell being lazy. If you did e.g. a map -> filter -> sum chain, the performance is not that great without lazy evaluation guaranteed by Haskell's implementation, which can complicate code in other scenarios or in the complexity of the compiler. OCaml is also an FP language, and the second example would be almost the same text, but with much worse performance. Also, Python is an OOP language, but a simple map implementation there is not much more verbose: def map(function, items): if len(items) != 0: return [function(items[0]), *map(function, items[1:])] return []
- epgui 4y agoI think the more pythonic way would probably be to use a list comprehension: def map(f, items): return [f(i) for i in items] These differences are all more about specific languages than about FP per se, however.
- teh64 4y agoTrue, but I tried to make it as close to the Haskell example as possible. I just think the OOP -> verbose/complex argument is really annoying, especially if it applies mostly to Java code.
- _old_dude_ 4y agoYes, this rings a bell :) But usually the issue is that people talk about OOP vs FP without specifying the scale, by example the Java stream API hide the mutations / side effects (not unlike Haskell monads do), so you can use { record, stream, functions, types } But internally it's still { mutability, side-effects }
- gjulianm 4y agoWithout going into the core of whether FP is better or not, if OOP/imperative is what 99.9% of people start with, you'll expect to have both FP advocates and skeptics coming from that background. It's just that FP skeptics have tried it and gone back. In other words, people only convert one way because it's the only way most people can convert.
- epgui 4y agoI understand what you're saying, but my point is that the near totality of FP criticism comes from people who don't know what they're talking about. ie.: you need to be very familiar with something before you can reasonably criticize it.
- nyanpasu64 4y agoWhen I go back to my old map/zip/method-chaining Rust code from a year or two ago, I regret doing so and wish I had written code as imperative sequential operations (looping over numeric ranges and container items, branching, and matching) like I write and understand today.