Hacker News new | ask | show | jobs
by AriaMinaei 2861 days ago
You're right. My examples should've been more complicated for regular functions not to be a suitable abstraction. Now, assume that the examples are complicated. In that case:

One method to define that function would be to do it the way explained in this [0] comment. That is, express the solution with small, composable functions. This would work as long as you can express the program in a composable way. This is what I usually try to do first, unless I find expressing my solution with composable pieces is not worth the effort.

For example, an async solution to a problem would be very difficult to express composably without well thought-out building blocks. One such collection of building block is Reactive Extensions [1], which is the result of years of research and development. So, before RX and similar libraries existed, it was costly to express async programs composably. That cost may or may not have been worth it.

Another method to define that function, if we're not going for "composable," would be to write it with an `options` argument, which would look something like:

  type Options = {use_cache: boolean, skip_one_cycle: boolean, number_of_retries: number, ...}
The more options one function has, the lengthier its definition would get, which means its core logic could be obfuscated. So that'd be the tradeoff with this method.

Third method would be to define multiple variants of that function, like `do_things()` and `do_things_with_cache()` and `do_things_and_retry()`, etc. Here, each function is simpler than a single function taking an `options` arg, but then core logic would be repeated in all of them.

And since these three methods are not binary options, one may even use all three of them to some extent.

What Optic seems to provide is a fourth option which allows you to forgo defining that function (as long as that makes sense) and repeat your core logic in many different parts of your code. The devtool would then recognize the core logic in all those different repetitions and assign it a single identity, which would allow you to manage that core logic from a single place. This would be especially useful in a language that does not support macros.

(Btw, macros would be your fourth option if you're coding in lisp/rust/etc. The one tradeoff with macros is that they are yet another layer of abstraction that the author and the reader of the code should keep in their head.)

[0] https://news.ycombinator.com/item?id=17792770

[1] http://reactivex.io/