counters
stobj
Major Section: STOBJ
Consider the event shown in stobj-example-1:
(defstobj counters (NodeCnt :type integer :initially 0) (TipCnt :type integer :initially 0) (IntTipsSeen :type t :initially nil))
Here is a complete list of the defuns added by the event.
The careful reader will note that the counters
argument below is
not declared with the :stobjs
xarg
even though we
insist that the argument be a stobj in calls of these functions.
This ``mystery'' is explained below.
(defun NodeCntp (x) ;;; Recognizer for 1st field (declare (xargs :guard t :verify-guards t)) (integerp x)) (defun TipCntp (x) ;;; Recognizer for 2nd field (declare (xargs :guard t :verify-guards t)) (integerp x)) (defun IntTipsSeenp (x) ;;; Recognizer for 3rd field (declare (xargs :guard t :verify-guards t) (ignore x)) t) (defun countersp (counters) ;;; Recognizer for object (declare (xargs :guard t :verify-guards t)) (and (true-listp counters) (= (length counters) 3) (NodeCntp (nth 0 counters)) (TipCntp (nth 1 counters)) (IntTipsSeenp (nth 2 counters)) t)) (defun create-counters () ;;; Creator for object (declare (xargs :guard t :verify-guards t)) (list '0 '0 'nil)) (defun NodeCnt (counters) ;;; Accessor for 1st field (declare (xargs :guard (countersp counters) :verify-guards t)) (nth 0 counters)) (defun update-NodeCnt (v counters) ;;; Updater for 1st field (declare (xargs :guard (and (integerp v) (countersp counters)) :verify-guards t)) (update-nth 0 v counters)) (defun TipCnt (counters) ;;; Accessor for 2nd field (declare (xargs :guard (countersp counters) :verify-guards t)) (nth 1 counters)) (defun update-TipCnt (v counters) ;;; Updater for 2nd field (declare (xargs :guard (and (integerp v) (countersp counters)) :verify-guards t)) (update-nth 1 v counters)) (defun IntTipsSeen (counters) ;;; Accessor for 3rd field (declare (xargs :guard (countersp counters) :verify-guards t)) (nth 2 counters)) (defun update-IntTipsSeen (v counters) ;;; Updater for 3rd field (declare (xargs :guard (countersp counters) :verify-guards t)) (update-nth 2 v counters))
Observe that there is a recognizer for each of the three fields and
then a recognizer for the counters
object itself. Then, for each
field, there is an accessor and an updater.
Observe also that the functions are guarded so that they expect a
countersp
for their counters
argument and an appropriate value
for the new field values.
You can see all of the defuns
added by a defstobj
event by
executing the event and then using the :pcb!
command on the stobj
name. E.g.,
ACL2 !>:pcb! counterswill print the defuns above.
We now clear up the ``mystery'' mentioned above. Note, for example
in TipCnt
, that the formal counters
is used. From the
discussion in stobj-example-1 it has been made clear that
TipCnt
can only be called on the counters
object. And yet,
in that same discussion it was said that an argument is so treated
only if it it declared among the :stobjs
in the definition of
the function. So why doesn't TipCnt
include something like
(declare (xargs :stobjs (counters)))
?
The explanation of this mystery is as follows. At the time
TipCnt
was defined, during the introduction of the counters
stobj, the name ``counters
'' was not yet a single-threaded
object. The introduction of a new single-threaded object occurs in
three steps: (1) The new primitive recognizers, accessors, and
updaters are introduced as ``ordinary functions,'' producing their
logical axiomatizations. (2) The executable counterparts are
defined in raw Lisp to support destructive updating. (3) The new
name is declared a single-threaded object to ensure that all future
use of these primitives respects the single-threadedness of the
object. The functions defined as part of the introduction of a new
single-threaded object are the only functions in the system that
have undeclared stobj formals other than state
.
You may return to stobj-example-1 here.