- Notifications
You must be signed in to change notification settings - Fork 273
Open
Labels
Description
When implementing Protocols using defrecord there are some missing affordances.
As an example, :pre and :post conditions cannot be applied.
[ Yes, I know we will soon have spec but these affordances will not be deprecated AFAIK. ]
Affordances not available on defrecord or deftype
(defprotocolSquarer (square [x])) (defrecordPosIntSquarer [x] Squarer (square [_] (* x x))) ; Usage (defprotocolSquarer (square [x])) ;=> Squarer (defrecordPosIntSquarer [x] Squarer (square [_] (* x x))) ;=> practice1.core.PosIntSquarer (square (->PosIntSquarer2)) ;=> 4;---^^^ All good (square (->PosIntSquarer"A")) ;CompilerException java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number, compiling:(.../core.clj:162:1) ;---^^^ We would like to prevent this using a simple assertion (defrecordPosIntSquarer [x] Squarer (square [_]{:pre [(pos-int? x)]} (* x x))) ;=> practice1.core.PosIntSquarer (square (->PosIntSquarer"A")) ;CompilerException java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number, compiling:(.../core.clj:162:1) ;---^^^ The pre-condition is being ignored (defrecordPosIntSquarer [x] Squarer (square [_]{:pre [(pos-int? x)] :post [(pos? %)]} (* x x))) CompilerException java.lang.RuntimeException: Unable to resolve symbol: % in this context, compiling:(.../core.clj:158:13) ;---^^^ The post condition compilation fail shows that all affordances are not available; Calling externally declared functions is one solution (defnpositive-square [x]{:pre [(pos-int? x)] :post [(pos? %)]} (* x x)) ;=> #'practice1.core/positive-square (defrecordPosIntSquarer [x] Squarer (square [_] (positive-square x))) ;=> practice1.core.PosIntSquarer (square (->PosIntSquarer"A")) ;CompilerException java.lang.AssertionError: Assert failed: (pos-int? x), compiling:(.../core.clj:163:1) Affordances are available via extend-protocol
(defrecordDirectSquarer [x]) => practice1.core.DirectSquarer (extend-protocol Squarer DirectSquarer (square [this]{:pre [(pos-int? (:x this))] :post [(pos? %)]} (* (:x this) (:x this)))) ;=> nil (square (->PosIntSquarer2)) ;=> 4 (square (->PosIntSquarer"A")) ;CompilerException java.lang.AssertionError: Assert failed: (pos-int? x), compiling:(.../core.clj:178:1) (square (->PosIntSquarer-2)) ;CompilerException java.lang.AssertionError: Assert failed: (pos-int? x), compiling:(.../core.clj:176:1) I don't want to claim this is a bug. But it's a sign that these options have pros and cons which are not currently well explained.
I would like to develop a more comprehensive table of features / affordances might be nicer than the current bullet list
metametadata