I've just made the code walker keep track of the types of transactions. So `try-put' which puts a value in a cell without blocking can be defined as:
(deftransaction try-put ((cell cell) val) (try (progn (put cell val) t) nil))
And the macroexpansion is:
(PROGN (EVAL-ALWAYS (PUSHNEW '(TRY-PUT NIL NIL) *TRANS-FUNS*)) (DEFMETHOD TRY-PUT ((CELL CELL) VAL) (ORELSE (TRANS (PROGN (UNTRANS (PUT CELL VAL)) T)) (TRANS NIL))) 'TRY-PUT)
So the code walker now knows that `orelse' takes two transactions as arguments. If you looked at the `pushnew' you would see some extra stuff. We're pushing '(try-put nil nil) instead of 'try-put. The two NILs means that `try-put' takes two arguments, both which aren't transactions.
Hey, have a look at the type of `orelse':
STM> (assoc 'orelse *trans-funs*) (ORELSE T T)
`orelse' takes two transactions as its arguments. Thats why its arguments are left inside a `trans'.
Neat huh?
This suggests a higher order operator called `nob' which turns any blocking action into a non-blocking one which returns t on success or nil on failure:
(deftransaction nob ((tx transaction)) (try (progn (funcall tx) t) nil))
However currently the macroexpansion doesn't work. The (funcall tx) form isn't untransed. I'm going to fix this up (the handling of funcall and apply), and extract the types from declarations.
Then we'll call it a summer.
Hoan