funcool / lentes

Functional references for Clojure and ClojureScript
https://cljdoc.org/d/funcool/lentes/CURRENT
BSD 2-Clause "Simplified" License
94 stars 10 forks source link

(satisfies? IAtom (l/focus-atom l/id (atom 5))) => false #1

Closed Kauko closed 8 years ago

Kauko commented 8 years ago

With lentes, two kinds of lenses can be created: two-way, writable lenses, and one-way, read-only lenses.

(def foobar (atom 5))
(def bar (l/focus-atom l/id foobar)) ;; has value 5
@foobar ; => 5
@bar ; => 5
(swap! foobar inc) ;; Both foobar and bar have value 6
(swap! bar inc) ;; Both have value 7

The bug is, bar does not satisfy IAtom:

(satisfies? IAtom bar) ;; false, should be true
(satisfies? IWatchable bar) ;; true
(satisfies? IReset bar) ;; true
(satisfies? ISwap bar) ;; true

There is another problem related to the read-only lenses.

(def foobar (atom 5))
(def read-only (l/focus-atom (l/getter identity) foobar)) ; has value 5
(swap! inc foobar) ;; Both have value 6
(swap! inc read-only) ;; Fails as it should, it's a read-only lense

(satisfies? IAtom read-only) ;false, should be true
(satisfies? IWatchable read-only) ; true
(satisfies? IReset read-only) ; true, should be false?
(satisfies? ISwap read-only) ; true, should be false?

So, three problems really:

  1. Lenses should satisfy IAtom
  2. Read-only lenses should not satisfy ISwap
  3. Read-only lenses should not satisfy IReset
niwinz commented 8 years ago

Thank you very much for the detailed explanation.

The issue 1, can be easy solved, so I'll fix it today. The issue 2 and 3 they are not easy to solve, because a lenses are just functions, in the same way as transducers are (they uses the same technique and they are composable in the same way). So there are no way to identify if a lense that receives the l/focus-atom is read only or not, because is just a function. This is because the returned atom is ISwap and IReset but throws an exception.

I think that trying to implement that checks will not have much value because the lenses are designed to be a generic approach for getters and setters and if some setter is not implemented, just and exception will be raised.

niwinz commented 8 years ago

Maybe I'll consider adding a third argument to focus-atom for explicitly return an atom that is read only independently of the received lense.

Kauko commented 8 years ago

That would make sense. I'd say the first issue is a true bug, and I'm happy to hear it's easy to fix.

The second and third issue is not as critical, because errors resulting from these flaws can be considered to be an user error; if I create a read-only lens, and then give it to something that expects it to be writable, that would absolutely be my fault, right?

However, if I had a way to give the lens a property that explicitly says it's read-only, then other parts of my program could rely on the ISwap and IReset checks to see whether the atom they receive is writable or not. So I like your idea of having the option to specify that the lens is read-only :)

niwinz commented 8 years ago

Nice, I'll try to do it today and rewrite some part of the doc for make it more easy for new comers ;)

niwinz commented 8 years ago

Released 1.1.0 with fixes for this issue.