pathom

:pathom: https://github.com/wilkerlucio/pathom/ & https://pathom3.wsscode.com & https://roamresearch.com/#/app/wsscode
wilkerlucio 2021-01-15T19:31:37.003600Z

hello everybody, I want to share with you some findings I just did. I'm working on the async support for Pathom 3, and this time I decided to compare two different implementations, one based in core.async and one based in promesa. I made the two implementations, and ran some benchmarks, here are the results: https://gist.github.com/wilkerlucio/a1cda78802c8a5f9cab92cb7c52fa69b

đź’Ż 1
🚀 3
wilkerlucio 2021-01-15T19:32:11.004Z

wilkerlucio 2021-01-15T19:32:54.004700Z

when I tried the core.async implementation I was a bit sad with the performance results, but than seeing those with Promesa made me really excited! the overhead using Promesa is quite close to the serial processing, which is a lot faster than every version of Pathom before that! and I would love to hear if have any opinions about this direction 🙏

imre 2021-01-15T21:01:57.006300Z

Impressive! Can it be made pluggable?

imre 2021-01-16T08:20:28.010200Z

This ^

wilkerlucio 2021-01-16T16:12:55.011700Z

I did some play here, and I checked its possible to also implement a promesa protocol to make other async things fulfill it, here is an example using core.async via said extension:

(extend-type cljs.core.async.impl.channels/ManyToManyChannel
  promesa.protocols/IPromiseFactory
  (-promise [this]
    (p/create
      (fn [resolve reject]
        (go
          (let [v (<! this)]
            (if (error? v)
              (reject v)
              (resolve v))))))))

(comment
  (let [start (system-time)]
    (-> (p.a.eql/process (pci/register
                           (pco/resolver 'foo {::pco/output [:foo-async]}
                             (fn [_ _] (go {:foo-async "the-value"}))))
          [:foo-async])

        (p/handle (fn [result error]
                    (println "RES" result error))))))

wilkerlucio 2021-01-16T16:16:38.012700Z

I probably wont provide this in the library to avoid having the dep on core.async at all, but it can be a separated library, or a documentation page with the snippet

wilkerlucio 2021-01-16T16:16:56.012900Z

what you think?

mpenet 2021-01-16T17:00:09.013500Z

Good approach. I really like core.async myself but having completablefutures is a good default, especially on the jvm. And it's easy to plug one into the others (you can make completablefuture impl for core. async readport/writeport that follows promise-chan impl, then overhead is really low I guess)

mpenet 2021-01-16T17:01:28.013700Z

I wouldn't bake in interceptor usage tho, this is more opinionated, there's no standard and there are multiple good impl. in clojure with subtle differences.

đź‘Ť 1
dehli 2021-01-19T13:10:15.014100Z

I think that’s a great solution! like you said it could be a separate library if there’s enough demand for it but it’s also a pretty small change that just mentioning it in the README should be enough

đź‘Ť 1
wilkerlucio 2021-01-15T21:20:24.006400Z

you can convert anything to a promise-like from promise, as long as you have some way to trigger the callbacks (for resolving or rejecting), so you could wrap a channel to make it do it. is this what you were asking about?

nivekuil 2021-01-15T22:20:44.007300Z

I like promesa too. I think it is really close to bare CompletableFuture overhead

2021-01-15T22:21:30.007800Z

Is it possible to provide channel coercion in pathom3?

2021-01-15T22:21:39.008100Z

then you could possibly get the best of both worlds

2021-01-15T22:22:15.008700Z

compatibility with core.async and performance of promesa

dehli 2021-01-15T22:22:25.009Z

it would be great if there could be one spot that we could do the channel -> promise conversion so that we could have our resolvers just return channels if we wanted

2021-01-15T22:22:26.009200Z

it might also be worth looking at kitchen-async(https://github.com/mhuebert/kitchen-async)

dehli 2021-01-15T22:24:02.009500Z

and then we can appropriately handle promise rejections in one spot as well since traditionally core async channels don’t really have a notion of “rejecting”

dehli 2021-01-15T23:24:41.009900Z

Something similar to how sieppari works would be awesome where by default it only supports promesa but you can bring in another namespace to extend what async libraries are supported (https://github.com/metosin/sieppari#external-async-libraries)