Drup / ocaml-lmdb

Ocaml bindings for lmdb.
https://drup.github.io/ocaml-lmdb/dev/
MIT License
48 stars 3 forks source link

Global transactions #11

Closed madroach closed 5 years ago

madroach commented 5 years ago

This PR contains #9 and #10

Let transactions span the whole environment

Transactions do span the whole environment and can be used for manipulations of any database and ever for creating / deleting databases. But until now their use was limited to only databases created by the containing Lmdb.S module. To remove this limitation, I put a Txn module at toplevel, which doesn't contain any database manipulating functions. The database manipulating functions (get, put, …) in the Make :S functor get an optional ?txn argument, to which a transaction created by the toplevel Txn module can be passed.

Performance is not affected.

madroach commented 5 years ago

Fuse the two transaction type right now (and split transaction and db arguments in the inner functions).

I'd pick this option, but what I'm actually aiming for is removing the old transaction interface completely. I just kept it for retro-compatibility.

Another delicate point is the encoding of the property we want. In particular, as it stands your cap type is not useful and the type of get could be simplified (see Txn.get). Do we want write-only transactions (even though lmdb doesn't really support them) ?

What I'm aiming for is this:

type 'a cap
val ro : [ `Read ] cap
val rw : [ `Read | `Write ] cap

Which will allow for subtyping, so that one may create ro transactions on rw environments or ro child-transactions to a rw parent …

Drup commented 5 years ago

The library is young and not used so much, we can afford to break compatibility, so if you think you have a good API with only the top level most general transactions and you can get rid of the other ones without removing functionalities, go for it.

Another thing you need to make sure is to be able to have top level database declarations that will not trigger the value restriction, as this would make the library quite hard to use for beginners.

madroach commented 5 years ago

Here's the PR without the inner Txn module. I also renamed CursorCrs and labelled the ~crs arguments. I did this just to make it more symmetric to the Txn and S signatures. I have no strong feelings about this. So if you like the long module name better or would rather drop the labels, tell so.

Drup commented 5 years ago

One small note on the use of labels (no need to fix it now, we can revisit it later): labels should always be placed leftmost. Since labels can only be swaped towards the right, placing them leftmost in the argument list ensure they can be placed anywhere.

madroach commented 5 years ago

labels can only be swaped towards the right

Could you elaborate this ? To me it seems like putting optional arguments right is more flexible:

# let f a ?(b=1) () = a+b;;
val f : int -> ?b:int -> unit -> int = <fun>
# let h ?(b=1) a = a+b;;
val h : ?b:int -> int -> int = <fun>
# f ~b:2 3 ();;
- : int = 5
# f 3 () ~b:2;;
- : int = 5
# f 3 ();;
- : int = 4
# (f 2) ~b:3 ();;
- : int = 5
# (h 2) ~b:3;;
Error: This expression has type int
       This is not a function; it cannot be applied.
Drup commented 5 years ago

That behavior is due to the fact that the presence of absence of optional argument is resolved when the last argument is applied. In f, it's (). In h, it's a. Add an extra argument to h, and the behavior will be the same.

Also, I would always write h instead of f. Adding a unit argument at the end of a function is only relevant when it only has labeled arguments. Otherwise, the "main" argument should come last, after all the labels.

madroach commented 5 years ago

I'm afraid I still don't get your point. How is it advantageous to put (optional?) labels leftmost?

As far as I can see it only makes a difference for partial applications. In partial applications optional arguments will be eliminated if they are leftmost, but will not be eliminated when they are further right. I prefer the latter behaviour.

Drup commented 5 years ago

Labels are very finicky, and putting them leftmost avoids most of the usual warts with their application. You'll have to believe me on that one, it's a lesson acquired rather painfully quite a long time ago. Beside, the whole community agrees on that one...