Hacker News new | past | comments | ask | show | jobs | submit login

Hm, I've used defs and bindings together inside macros to reduce redundant args like this function here: https://github.com/shriphani/clj-lmdb/blob/master/src/clj_lm...

I think brevity is far more important than being explicit all the time. When we speak, we use a lot of context to infer what is said - no reason code shouldn't look like that.




The problem with that is that if `put!` or some other function is used inside `map` or some other lazy context, it may get realized outside the context of `with-read-txn`. Making `binding` part of your public API breaks referential transparency.


So what would you recommend that function look like? I think it is bad taste to say (with-read-txn db-name (put! db-name)) - no reason you should specify again what db you are dealing with.


There's plenty of reason: you can put any code you like inside of `with-read-txn`, including closures that are evaluated lazily. If you dislike the duplication, create a syntactic form that allows less, like this:

    (transaction-> db-name
      (put! ...)
      ...)
This doesn't lend itself to every kind of action, but it is narrower. Alternately, create a variadic version of `put!` which guarantees eager evaluation inside of a transaction.

The nightmare scenario here is not that the sequence will lazily evaluate outside of `with-read-txn`, because that at least will throw an error. Rather, it's that it will be evaluated inside a different transaction, without anyone ever realizing it. By leaving that possibility open, you're doing a huge disservice to the users of your library.


Ok I see your point. I am curious how that would happen though - essentially you'll need to bind the txn to a different transaction from the one intended and the whole thing locks up.

I am curious how to guarantee eager evaluation - dorun, doall and run! are all sequence-oriented right?


It's not that hard to imagine: map a `get` over a series of keys inside a transaction, return that lazy sequence, and use the results to do another series of operations within a different transaction.

Libraries typically can't guarantee eager evaluation, since that's a property of the top-level execution. That's why libraries shouldn't use `binding`.


Funnily enough, I think I picked up this habit from Korma source: https://github.com/korma/Korma/blob/master/src/korma/db.clj#...


Wow I am not sure how I missed that - thanks for pointing it out. The (transaction-> ###) pattern looks a lot nicer to me. Really appreciate the help.




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: