The careful reader will note that the counters argument below is
not declared with the :stobjsxarg even though we
insist that the argument be a stobj in calls of these functions.
This ``mystery'' is explained below.

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! counters

will 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.