{Begin SubSec Reusing Boxed Numbers in Interlisp-10 - SETN} {Title Reusing Boxed Numbers in Interlisp-10 - SETN} {Text {index *BEGIN* SETN FN} {index boxing} {fn RPLACA} and {fn RPLACD} provide a way of cannibalizing list structure for reuse in order to avoid making new structure and causing garbage collections.{foot The nobox package provides a more aesthetic way of reusing cons cells as well as number boxes. However, it is still the case that techniques involving reusing static storage should be used with extreme caution, and be reserved for those cases where the normal method of storage allocation and garbage collection is not workable or practical. The decl package ({PageRef Tag DECL}) takes a different approach to the same problem by avoiding creating number boxes in the first place via type declarations in the body of the function definition. }{Comment Endfootnote} This section describes an analogous function in Interlisp-10 for reusing large integers{index large integers} and floating point numbers,{index floating point numbers} {fn SETN}. {fn SETN} is used like {fn SETQ}, i.e., its first argument is considered as quoted, its second is evaluated. If the current value of the variable being set is a large integer or floating point number, the new value is deposited into that word in number storage, i.e., no new storage is used.{foot The second argument to {fn SETN} must always be a number or a {lisp NON-NUMERIC ARG} error is generated. }{comment endfootnote} If the current value is {it not} a large integer or floating point number, e.g., it can be {lisp NIL}, {fn SETN} operates exactly like {fn SETQ}, i.e., the large integer or floating point number is boxed, and the variable is set. This eliminates initialization of the variable. {fn SETN} will work interpretively, i.e., reuse a word in number storage, but will not yield any savings of storage because the {index boxing}boxing of the second argument will still take place, when it is evaluated. The elimination of a box is achieved only when the call to {fn SETN} is compiled, since {fn SETN} compiles open, and does not perform the box if the old value of the variable can be reused. {Begin SubSec Caveats concerning use of SETN} {Title Caveats concerning use of SETN} {Text There are three situations to watch out for when using {fn SETN}. The first occurs when the same variable is being used for floating point numbers and large integers. If the current value of the variable is a floating point number, and it is reset to a large integer, via {fn SETN}, the large integer is simply deposited into a word in floating point number storage, and hence will be interpreted as a floating point number. Thus, {lispcode ←(SETQ FOO 2.3) 2.3 ←(SETN FOO 10000) 2.189529E-43 } Similarly, if the current value is a large integer, and the new value is a floating point number, equally strange results occur. The second situation occurs when a {fn SETN} variable is reset from a large integer to a small integer. In this case, the small integer is simply deposited into large integer storage. It will then print correctly, and function arithmetically correctly, but it is {it not} a small integer, and hence will not be {fn EQ} to another integer of the same value, e.g., {lispcode ←(SETQ FOO 10000) 10000 ←(SETN FOO 1) 1 ←(IPLUS FOO 5) 6 ←(EQ FOO 1) NIL ←(SMALLP FOO) NIL } In particular, note that {fn ZEROP} will return {lisp NIL} even if the variable is equal to 0. Thus a program which begins with {lisp FOO} set to a large integer and counts it down by {lisp (SETN FOO (SUB1 FOO))} must terminate with {lisp (EQP FOO 0),} not {lisp (ZEROP FOO)}. Finally, the third situation to watch out for occurs when you want to save the current value of a {fn SETN} variable for later use. For example, if {lisp FOO} is being used by {fn SETN}, and the user wants to save its current value on {lisp FIE}, {lisp (SETQ FOO FIE)} is not sufficent, since the next {fn SETN} on {lisp FOO} will also change {lisp FIE}, because its changes the word in number storage pointed to by {lisp FOO}, and hence pointed to by {lisp FIE}. The number must be copied, e.g., {lisp (SETQ FIE (IPLUS FOO))}, which sets {lisp FIE} to a new word in number storage. {FnDef {FnName SETN} {FnArgs VAR X} {Type NLAMBDA} {Text A nlambda function like {fn SETQ}. {arg VAR} is quoted, {arg X} is evaluated, and its value must be a number. {arg VAR} will be set to this number. If the current value of {arg VAR} is a large integer or floating point number, that word in number storage is cannibalized. The value of {fn SETN} is the (new) value of {arg VAR}. }} }{End SubSec Caveats concerning use of SETN} {index *END* SETN FN} }{End SubSec Reusing Boxed Numbers in Interlisp-10 - SETN} {Begin SubSec Box and Unbox in Interlisp-10} {Title Box and Unbox in Interlisp-10} {Text Some applications may require that a user program explicitly perform the {index boxing}boxing and {index unboxing}unboxing operations that are usually implicit (and invisible) to most programs. The functions that perform these operations are {index LOC FN}{fn LOC} and {index VAG FN}{fn VAG} respectively. For example, if a user program executes a {index TENEX}TENEX JSYS using the {index ASSEMBLE FN}{lisp ASSEMBLE} directive, the value of the {lisp ASSEMBLE} expression will have to be boxed to be used arithmetically, e.g., {lisp (IPLUS X (LOC (ASSEMBLE --)))}. It must be emphasized that {it Arbitrary unboxed numbers should {it NOT} be passed around as ordinary values because they can cause trouble for the garbage collector. } {index unboxed numbers} For example, suppose the value of {lisp X} were 150000, and you created {lisp (VAG X)}, and this just {it happened} to be an address on the free storage list. The next garbage collection could be disastrous. For this reason, the function {index VAG FN}{fn VAG} must be used with extreme caution when its argument's range is not known. {fn LOC} is the inverse of {fn VAG}. It takes an address, i.e., a 36 bit quantity, and treats it as a number and boxes it. For example, {index LOC FN}{fn LOC} of an atom, e.g., {lisp (LOC (QUOTE FOO))}, treats the atom as a 36 bit quantity, and makes a number out of it. If the address of the atom {lisp FOO} were 125000, {lisp (LOC (QUOTE FOO))} would be 125000, i.e., the location of {lisp FOO}. It is for this reason that the {index box}box operation is called {index LOC FN}{fn LOC}, which is short for location. Note that {lisp FOO} does not print as {lisp #364110} (125000 in octal) because the print routine recognizes that it is an atom, and therefore prints it in a special way, i.e., by printing the individual characters that comprise it. Thus {lisp (VAG 125000)} would print as {lisp FOO}, and would in fact {it be} {lisp FOO}. {FnDef {FnName LOC} {FnArgs X} {Text Makes a number out of {arg X}, i.e., returns the location of {arg X}. }} {FnDef {FnName VAG} {FnArgs X} {Text The inverse of {fn LOC}. {arg X} must be a number; the value of {fn VAG} is the unbox of {arg X}. }} The compiler eliminates extra {fn VAG}'s and {fn LOC}'s for example {lisp (IPLUS X (LOC (ASSEMBLE --)))} will not box the value of the {lisp ASSEMBLE}, and then unbox it for the addition. }{End SubSec Box and Unbox in Interlisp-10}