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?
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?
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 }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 xsBuilding FP functionality with classes sounds just as fun as building java classes with assembly.
The first "final", the "StatelessOp", the "StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT", the "int flags" are all here because of 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 [] 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.The only thing unique about the Haskell example, I think, was pattern-matching... And while that's nice, you don't really need that for FP.
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 }In other words, people only convert one way because it's the only way most people can convert.
ie.: you need to be very familiar with something before you can reasonably criticize it.
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.