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