Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

You can do many FP things in Java as well, as it is a multi-paradigm language, hell, Kotlin is not even particularly functional-y.


I'll agree that Kotlin is not hardcore FP (although you can get there some of the way with Arrow etc.), but FP in Java is clunky.

- Having to remember the difference between "Function", "Consumer", "Predicate" and "Supplier" is weird. In Kotlin (and basically every other typed FP language that I know), I just write the type signature the natural way.

- Having to use streams in order to use map, etc., is noisy. Why weren't these APIs retrofitted to collections?

- Checked exceptions are a pain with functional code, e.g. map.

- Mutability is still the default behaviour of almost everything in Java, save records (and strings).

etc.


> Having to use streams in order to use map, etc., is noisy. Why weren't these APIs retrofitted to collections?

Sure, methods along the lines of the following could have been added:

  public <R> List<R> map(Function<? super E, ? extends R> mapper) {
      return stream().map(mapper).toList();
  }
Yes, having them would make Java less verbose in the case where you only want to do a single map, filter, whatever operation on a collection, but I'm personally glad that they weren't because they produce extremely inefficient behavior when chained. So, it would add a performance footgun to save ~18 characters.


But are these things enough to warrant me a full switch of programming language and ecosystem? Not for me.

- I don’t think this is really that big of a deal.

- Using streams is actually preferred so you don’t cause a performance nightmare and kotlin you has to use asSequence anyway.

- I thought checked error handling was all the rage nowadays?

- Mutability is absolutely fine if you’re not going over a thread boundary.


In Kotlin, asSequence gives you lazy behaviour (i.e. chains of map, filter, etc. are merged the way it's automatically done in Haskell), but if you don't care about the performance penalty, you can just call map, filter etc. on eager collections too. I'm of the opinion that you shouldn't prematurely optimise, for small enough data, it often doesn't matter much.

And checked exceptions are widely seen as an anti-feature - I don't think any other language has them, with the possible exception of Swift (see below), and for good reason. Other languages encode errors (more or less ergonomically) in the type system (e.g. Rust, Haskell, and to an extent it's what Kotlin advocates as well), and that has the advantage of playing well together with other language mechanisms - e.g. no extra allowances need to be made so that map works with them.

But for the sake of the argument: Swift also has something similar to checked exceptions, but only in the sense that functions can either throw or not throw. However, Swift also at least has constructs like "rethrows", which lets you say that a function such as map should throw iff the higher order function it wraps throws.

Java simply decided that it doesn't need to deal with this problem at all (for whatever reason - they simply could have added something like "rethrows") and now it's up to callers to deal with the incredible awkwardness that is using FP with Java library code that makes heavy use of checked exceptions.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: