code-reviews

Ben Sless 2021-11-13T09:42:51.025500Z

@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

seancorfield 2021-11-13T17:00:52.025700Z

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

Ben Sless 2021-11-13T17:02:59.025900Z

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

seancorfield 2021-11-13T17:03:23.026100Z

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?

seancorfield 2021-11-13T17:08:00.026300Z

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)?

seancorfield 2021-11-13T17:08:46.026500Z

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

seancorfield 2021-11-13T17:10:17.026700Z

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

Ben Sless 2021-11-13T17:19:50.027Z

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

Ben Sless 2021-11-13T17:20:09.027200Z

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

Ben Sless 2021-11-13T17:20:41.027400Z

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 Sless 2021-11-13T17:20:58.027600Z

Then the components appear very "vanilla"

Ben Sless 2021-11-13T17:21:43.027800Z

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

Ben Sless 2021-11-13T17:22:34.028Z

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 Sless 2021-11-13T17:23:56.028200Z

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 Sless 2021-11-13T17:24:29.028400Z

no boilerplate, no wrapping, and no difference in semantics

seancorfield 2021-11-13T17:27:03.028600Z

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?

seancorfield 2021-11-13T17:27:48.028800Z

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 Sless 2021-11-13T17:31:32.029Z

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 Sless 2021-11-13T17:40:07.029300Z

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