Fork me on GitHub
#sql
<
2023-12-11
>
isak15:12:09

If I reduce a next.jdbc plan without providing an init val (`(reduce f (next.jdbc/plan ...))`), I get this error: class next.jdbc.result_set$eval26051$fn$reify__26053 cannot be cast to class clojure.lang.IReduce Passing in nil for the init val makes it work as expected. Is that how it is supposed to work?

seancorfield16:12:31

Yes. There is no sensible default so that form of reduce is not supported on plan. Pretty sure the docs explicitly call that out (but I'm on my phone right now).

👌 1
dpsutton16:12:32

doc doesn’t mention it > Returns a reducible that but source clearly indicates it

(^clojure.lang.IReduceInit
    [stmt]
    (p/-execute stmt [] {}))

👌 1
seancorfield16:12:17

In Getting Started, it says plan returns an IReduceInit but that's probably not quite clear enough. I'll update the docs and the docstring.

👍 1
isak16:12:20

Ok I see. Yea I checked what the clojure interfaces for reduce were after writing this, but wouldn't have known that that meant only the init val arity was supported.

isak16:12:10

For a sensible default, would [] be wrong? (Since a result set is like a collection / seq)

dpsutton16:12:34

if you intend to accumulate rows, yes. if you intend to sum something, no. If you intend to get stats in a map, no. etc.

isak16:12:32

Right but that isn't the default thing you get from a result set, so it makes sense that you would override the default in such cases

isak16:12:57

I think nil might be another value that some people would reasonably expect to be the default though, so the fact that there are 2 sensible values might be reason enough for the existing logic.

isak16:12:44

@U11BV7MTK isn't that an argument against IReduce in principle though?

dpsutton16:12:51

yes it is 🙂

😨 1
dpsutton16:12:27

but here fits that general argument i think

seancorfield16:12:02

Rich has said that the non-init form of reduce was a mistake.

isak16:12:43

Ah, fair enough

dpsutton16:12:06

nil as a default would accumulate rows in reverse order. a transient is probably a good call here as well but requires the reducing function to play along. far better to just own the initial value

isak16:12:29

I see the benefits and generally do that. The downside is the surprise - not working like reduce normally.

dpsutton16:12:20

reduce without an init is really weird

dpsutton16:12:52

> If val is not supplied, > returns the result of applying f to the first 2 items in coll, then > applying f to that result and the 3rd item, etc. If coll contains no > items, f must accept no arguments as well, and reduce returns the > result of calling f with no arguments. If coll has only 1 item, it > is returned and f is not called. If val is supplied, returns the > result of applying f to val and the first item in coll, then > applying f to that result and the 2nd item, etc. If coll contains no > items, returns val and f is not called. the docstring of reduce is convoluted to talk about the lack of an init. and is quite surprising

isak16:12:58

Hmm yea you're right, that is very strange

seancorfield17:12:31

OK, docs and docstrings are updated for the next release.

💯 1