5 ms·
aObservable.filter(n -> n % 2 == 0) .map(n -> n * n) .subscribe(System.out::println); I love functional programming, but there's something that a FP
by lemevi 11y ago
aObservable.filter(n -> n % 2 == 0)
.map(n -> n * n)
.subscribe(System.out::println);
I love functional programming, but there's something that a FP programming language Haskell brings to it that you don't wont get in attempts to bring FP to other languages, and that's lazy evaluation.
For example, when using FP in other languages I worry about how the functions I stack together to evaluate lists are implemented. I sincerely doubt that they have Haskell's optimizations and are actually continuously and unnecessarily iterating over everything in each function call multiple times.
Haskell doesn't actually do this even though that's how the code might read. So while I love declarative programming and writing and using functions that don't have side-effects I'm not sure that unless it's supported by the actual engine powering the language that it's the best idea. In fact it may be a bit cargo-cult programming, it looks like FP, but it doesn't actually work like FP.
Additionally, regarding the observer pattern in my experience that leads to tightly coupled code where you can't always easily trace the line of execution or separate it out later when you need to. It's like global streams of communication, sort of like using global variables to pass state around. I can't tell from the article if they've addressed that.
- cwyers 11y agoThat's more of a Haskell thing than an overall functional language thing, isn't it? OCaml uses strict evaluation.
- bbatha 11y agoThough OCaml supports lazy very well with the lazy keyword.
- davexunit 11y agoFunctional programming is orthogonal to lazy or eager evaluation.
- hepta 11y agoBoth Clojure and Scala work on the JVM, both have lazy sequences, Scala even has lazy evaluation. It's not the same as fusion, but it's not unnecessary iteration either. These are not invalidated by being on the JVM, Java can do some of these as well.
- jerven 11y agoI know that the Graal JIT guys are working on chained function call fusing for inlining when generating machine code etc... But I am not sure that is what you call "fusion". There is definitely only one iteration over the collection in the example style code.
- hepta 11y agoStream fusion (in Haskell) is the removal of intermediate lists created when you chain multiple list functions (map, filter, fold, etc). https://donsbot.wordpress.com/2008/06/04/haskell-as-fast-as-c-working-at-a-high-altitude-for-low-level-performance/ https://donsbot.wordpress.com/2008/06/04/haskell-as-fast-as-...
- edgyswingset 11y ago> For example, when using FP in other languages I worry about how the functions I stack together to evaluate lists are implemented. I'm only speaking for languages I know: - C# LINQ API via IEnumerable<T> is lazy (aside from a few like Min/Max) - F# is lazy for any Seq functions or the Lazy() computation - Clojure is lazy for Sequence functions You can verify all three by looking at the source on Github if you'd like.
- V-2 11y agoA big loser here (in my opinion) is Kotlin, whose equivalent of LINQ doesn't support deferred evaluation
- muraiki 11y ago> Additionally, regarding the observer pattern in my experience that leads to tightly coupled code where you can't always easily trace the line of execution or separate it out later when you need to. That's definitely a danger. When I use the simpler (compared to Rx) Observables in Knockout.js, I make sure to keep my ViewModels small and single-purpose, which helps address this problem. When I used RxJS with Cycle.js, you can kind of do something similar using widgets, but it seems like it might be harder since a widget in Cycle isn't supposed to have any domain logic. I know Cycle's author recently posted a fairly large example in use at his company's site, so maybe that shows the way to structure things.
- smadge 11y ago> continuously and unnecessarily iterating over everything in each function call multiple times. There is nothing to iterate over in Rx. An Observable is NOT a list. It can be an asynchronous sequence, for instance a sequence of mouse clicks, or events from a websocket. All it does is call onNext on the subscribed Observers. So it's not as if chaining a map and then a filter iterates over a collection twice. In your example, when the source Observable emits a new value, it calls onNext for the FilterObservable, which then calls onNext for the MapObservable.