architecture

vemv 2021-02-23T15:18:05.005900Z

Anyone has a success story using Results (as explained in https://timofreiberg.github.io/clojure-vs-rust)? For many years I've stayed away from them because they seemed a gateway drug for monads :) and personally I'm not particularly interested in them. The thing that makes me think is - in the end a "Result" it just a hashmap, and Clojure is great at hashmaps. And as of the last few years with clojure.spec, we've gotten even better at them. So can't one use Results without going as far as introducing a different paradigm, custom macros, etc? e.g. just treat the hashmap as any other application-level hashmap.

gklijs 2021-02-25T11:27:06.009500Z

Yes, and in Rust your whole application is kind of one big pipeline, where undefined error handling leads to a crash. In Clojure the needs is much less.

👀 1
2021-03-03T15:41:32.011200Z

I'm not a fan of the result pattern in clojure, because at the end you still have to handle exceptions which can always happen. So I prefer to just use exceptions all the time

2021-03-03T16:51:23.011400Z

Yeah I agree generally. Embrace the exceptions. You cannot rid yourself of them.

Shantanu Kumar 2021-02-23T15:36:53.006Z

Statically typed languages can “compile away” the overhead of distinguishing value vs failure/error. In Clojure you end up wrapping both value and failure/error in a proper monad, so (shameless plug) https://github.com/kumarshantanu/promenade takes a hybrid approach by only wrapping the failure/error. The overhead of composing over the abstraction still remains though.

👍 1
gklijs 2021-02-23T16:44:08.006600Z

The nice thing with results is that they are consistently used among crates. So in https://github.com/gklijs/schema_registry_converter is can easily handle ‘any error’. Not entirely true of course. In this case the user of this crate is still in control on what ‘finally’ happens to the error. And depending on where the error occurred it might be cashed, so it doesn’t keep doing the same failing http call (at least that’s one of the possible scenario’s). If it was implemented consistently in clojure, it would be nice. But with clojure you sometimes get a nil, and sometimes a Runtime exeption when things go bad. And in some cases a map..

👍 1
seancorfield 2021-02-23T18:02:14.007200Z

We have a couple of contexts at work where we pass a hash map through a pipeline of transformations and processes (as the first argument to those functions) and that hash map includes a :valid Boolean field which all the processes check before proceeding -- which is essentially that result pattern. It's useful in specific situations but I wouldn't want to work with generic code that supported that approach at its core (years ago I created a library called Engine to support writing generic code that had "sources" and "sinks" and separated pure functions from effects -- but the code built using it was far too monadic in style for my taste).

👍 1
vemv 2021-02-23T18:10:44.007500Z

The :valid key is a neat idea - a lot of clojure processing is already hashmap-based, so one wraps nothing (likewise, one could add metadata to vectors if feeling extra adventurous) It also resonates with RH's ideal of mixing keys of various provenance under the same hashmap.

2021-02-23T20:25:28.007700Z

Yeah I’ve used {:val ..} / {:errs […]} to good effect.

2021-02-23T20:25:45.007900Z

you can cram more context keys into either one

2021-02-23T20:26:50.008100Z

But I absolutely do not recommend doing it on a wide scale. Like Sean said, my usage is deep in a transformation pipeline where things need to get propagated up the stack.

👀 1
2021-02-23T20:27:03.008300Z

Rare case, but it does exist.