Fork me on GitHub
#code-reviews
<
2021-11-13
>
Ben Sless09:11:51

@seancorfield I remember some time ago we talked about the best way to mix components which we would want to implement protocols without a lot of boilerplate. My idea was to work with a component which still satisfied some framework protocols (like reitit's router) without change to the semantics. Came up with this, what do you think? https://gist.github.com/bsless/db15d79f4ec9acac92e18db8fba27135

seancorfield17:11:52

Should the second opts in line 17 be opts+specs? Otherwise that argument doesn't seem to be used?

Ben Sless17:11:59

Oh, right, I renamed the macro argument but forgot to update the binding

seancorfield17:11:23

My personal feeling is that this is too much "magic" and it makes it very hard to just look at code and figure out what it actually does. I mean, how often do you really need a record to implement an arbitrary list of protocols -- and what are those implementations actually doing in this case?

seancorfield17:11:00

OK, so macroexpand-1 seems to indicate this is just adding delegation of those protocols via the first field of the record -- but I don't understand why. What's the motivation for this (the discussion was some time ago)?

seancorfield17:11:46

Also, if we're talking about Component, we're tending to implement Lifecycle via metadata a lot these days at work -- not records.

seancorfield17:11:17

(although, unfortunately, IKVReduce doesn't support extension via metadata)

Ben Sless17:11:50

It's a balancing act between readability, convenience and "magic"

Ben Sless17:11:09

Let's say I want to bring in something like a malli registry or reitit router as a component

Ben Sless17:11:41

I can extend them via metadata, or I can just stick them as a "state" in a component and delegate their methods to them

Ben Sless17:11:58

Then the components appear very "vanilla"

Ben Sless17:11:43

They just have a list of "here are all the protocols (and interfaces?) I delegate to"

Ben Sless17:11:34

When I settle on how I want to do interfaces, too, I get a convenient way of delegating over java objects, too, which I can't extend via metadata

Ben Sless17:11:56

But take next.jdbc as another example, I can just specify a list of protocols on a record and it can "automagically" participate in them

Ben Sless17:11:29

no boilerplate, no wrapping, and no difference in semantics

seancorfield17:11:03

What next.jdbc protocols would you want to delegate to? That's not a compelling argument to me. next.jdbc.connection/component already exists for making a Component that wraps a pooled datasource. What other things would you want to do?

seancorfield17:11:48

This is just not a problem I've run into, so maybe it's specific to a couple of the libraries you're using that sort of expect you to implement a bunch of protocols with boilerplate?

Ben Sless17:11:32

I can give several examples • with next.jdbc I might not want to use the component wrapper, just due to preference • https://github.com/metosin/reitit/blob/master/modules/reitit-core/src/reitit/core.cljc#L38https://github.com/metosin/malli/blob/master/src/malli/registry.cljc#L8

Ben Sless17:11:07

The router example - depends on handlers. Handlers might be stateful (they might call a db)