{Begin Chapter Data Types}
{Title Data Types}
{Text




Interlisp is a system for the manipulation of various kinds of data; it provides a large set of built-in data types, which may be used to represent a variety of abstract objects, and the user can also define new data types which can be used exactly like built-in data types.


{index *BEGIN* type names}

Each data type in Interlisp has an associated "type name," a litatom.{foot
In Interlisp-10, each data type also has an associated "type number."  See {PageRef Fn NTYP}.
}{comment endfootnote}
Some of the type names of built-in data types are:  {lisp LITATOM}, {lisp LISTP}, {lisp STRINGP}, {lisp ARRAYP}, {lisp STACKP}, {lisp SMALLP}, {lisp FIXP}, and {lisp FLOATP}.  For user data types ({PageRef Tag UserDataTypes}), the type name is specified when the data type is created.


{FnDef {FnName DATATYPES} {FnArgs {anonarg}}
{Text
Returns a list of all type names currently defined.

{note if arg USERSFLG=non-NIL, doesn't include built-in data types. doc?}
}}


{FnDef {FnName TYPENAME} {FnArgs DATUM}
{Text
Returns the type name for the data type of {arg DATUM}.
}}


{FnDef {FnName TYPENAMEP} {FnArgs DATUM TYPENAME}
{Text 
Returns {lisp T} if {arg DATUM} is an object with type name equal to {arg TYPENAME}, otherwise {lisp NIL}.
}}


Note:  {fn TYPENAME} and {fn TYPENAMEP} distinguish the logical data types {lisp ARRAYP}, {lisp CCODEP} and {lisp HARRAYP}, even though they may be implemented as {lisp ARRAYP}s in some Interlisp implementations.

{index *END* type names}



{Begin SubSec Data Type Predicates}
{Title Data Type Predicates}
{Text


Interlisp provides seperate functions for testing whether objects are of certain commonly-used types:


{FnDef {FnName LITATOM} {FnArgs X}
{Text
Returns {lisp T} if {arg X} is a litatom,{index litatom Term} {lisp NIL} otherwise.  Note that a number is not a litatom. 
}}



{FnDef {FnName SMALLP} {FnArgs X}
{Text
Returns {arg X} if {arg X} is a small integer;{index small integers} {lisp NIL} otherwise.  (Note that the range of small integers is implementation-dependent.  See {PageRef Tag SmallIntegers}.)
}}


{FnDef {FnName FIXP} {FnArgs X}
{Text
Returns {arg X} if {arg X} is a small or large integer (between {var MIN.FIXP} and {var MAX.FIXP}); {lisp NIL} otherwise.{index integers}{index small integers}{index large integers}
}}


{FnDef {FnName FLOATP} {FnArgs X}
{Text
Returns {arg X} if {arg X} is a floating point number;{index floating point numbers} {lisp NIL} otherwise.
}}

{FnDef {FnName NUMBERP} {FnArgs X}
{Text
Returns {arg X} if {arg X} is a number{index numbers} of any type ({lisp FIXP} or {lisp FLOATP}), {lisp NIL} otherwise.
}}


{FnDef {FnName ATOM} {FnArgs X}
{Text
Returns {lisp T} if {arg X} is an atom{index atom} (i.e. a litatom or a number); {lisp NIL} otherwise.

Warning:  {lisp (ATOM {arg X})} is {lisp NIL} if {arg X} is an array, string, etc.  In many dialects of Lisp, the function {fn ATOM} is defined equivalent to the Interlisp function {fn NLISTP}.
}}


{FnDef {FnName LISTP} {FnArgs X}
{Text
Returns {arg X} if {arg X} is a list cell,{index list cells} e.g., something created by {fn CONS}; {lisp NIL} otherwise.
}}


{FnDef {FnName NLISTP} {FnArgs X}
{Text
{lisp (NOT (LISTP X))}.  Returns {lisp T} if {arg X} is not a list cell, {lisp NIL} otherwise.
}}


{FnDef {FnName STRINGP} {FnArgs X}
{Text
Returns {arg X} if {arg X} is a string,{index strings} {lisp NIL} otherwise.
}}


{FnDef {FnName ARRAYP} {FnArgs X}
{Text
Returns {arg X} if {arg X} is an array,{index arrays} {lisp NIL} otherwise.

Note:  In most current implementations of Interlisp, {fn ARRAYP} may also return {arg X} if it is of type {lisp CCODEP} or {lisp HARRAYP}.
}}


{FnDef {FnName HARRAYP} {FnArgs X}
{Text
Returns {arg X} if {arg X} is a hash array,{index hash arrays} {lisp NIL} otherwise.
}}



Note:  The empty list, {lisp ()} or {lisp NIL},{index NIL Litatom} is considered to be a litatom, rather than a list.  Therefore, {lisp (LITATOM NIL)} = {lisp (ATOM NIL)} = {lisp T} and {lisp (LISTP NIL)} = {lisp NIL}.  Care should be taken when using these functions if the object may be the empty list {lisp NIL}.

}{End SubSec Data Type Predicates}





{Begin SubSec Data Type Equality}
{Title Data Type Equality}
{Text


A common operation when dealing with data objects is to test whether two objects are equal.  In some cases, such as when comparing two small integers, equality can be easily determined.  However, sometimes there is more than one type of equality.  For instance, given two lists, one can ask whether they are exactly the same object, or whether they are two distinct lists which contain the same elements.  Confusion between these two types of equality is often the source of program errors.  Interlisp supplies an extensive set of functions for testing equality:



{FnDef {FnName EQ} {FnArgs X Y}
{Text
Returns {lisp T} if {arg X} and {arg Y} are identical pointers; {lisp NIL} otherwise.  {fn EQ} should not be used to compare two numbers, unless they are small integers; use {fn EQP} instead.

{note it is safe to use EQ for litatoms and small integers --- for all other objects you can have copies---so be careful}
}}


{FnDef {FnName NEQ} {FnArgs X Y}
{Text
{lisp (NOT (EQ {arg X} {arg Y}))}
}}


{FnDef {FnName NULL} {FnArgs X}}
{FnDef {FnName NOT} {FnArgs X}
{Text
{lisp (EQ {arg X} NIL)}
}}



{FnDef {FnName EQP} {FnArgs X Y}
{Text
{index *PRIMARY* EQP Fn}Returns {lisp T} if {arg X} and {arg Y} are {fn EQ}, or if {arg X} and {arg Y} are numbers and are equal in value; {lisp NIL} otherwise.  For more discussion of {fn EQP} and other number functions, see {PageRef Tag Numbers}.

Note:  {fn EQP} also can be used to compare stack pointers ({PageRef Tag EQPStackPointers}) and compiled code ({PageRef Tag EQPCompiledCode}).
}}



{FnDef {FnName EQUAL} {FnArgs X Y}
{Text
{fn EQUAL} returns {lisp T} if {arg X} and {arg Y} are (1) {fn EQ}; or (2) {fn EQP}, i.e., numbers with equal value; or (3) {fn STREQUAL}, i.e., strings containing the same sequence of characters; or (4) lists and {fn CAR} of {arg X} is {fn EQUAL} to {fn CAR} of {arg Y}, and {fn CDR} of {arg X} is {fn EQUAL} to {fn CDR} of {arg Y}.  {fn EQUAL} returns {lisp NIL} otherwise.  Note that {fn EQUAL} can be significantly slower than {fn EQ}.

A loose description of {fn EQUAL} might be to say that {arg X} and {arg Y} are {fn EQUAL} if they print out the same way.{note but...  exceptions to point out??}
}}


{FnDef {FnName EQUALALL} {FnArgs X Y}
{Text
Like {fn EQUAL}, except it descends into the contents of arrays, hash arrays, user data types, etc.  Two non-{fn EQ} arrays may be {fn EQUALALL} if their respective componants are {fn EQUALALL}.
}}


}{End SubSec Data Type Equality}




{Begin SubSec "Fast" and "Destructive" Functions}
{Title "Fast" and "Destructive" Functions}
{Text

Among the functions used for manipulating objects of various data types, there are a number of functions which have "fast" and "destructive" versions.  The user should be aware of what these functions do, and when they should be used.

{index fast functions}

"Fast" functions:  By convention, a function named by prefixing an existing function name with {lisp F} indicates that the new function is a "fast" version of the old.  These usually have the same definitions as the slower versions, but they compile open and run without any "safety" error checks.  For example, {fn FNTH} runs faster than {fn NTH}, however, it does not make as many checks (for lists ending with anything but {lisp NIL}, etc).  If these functions are given arguments that are not in the form that they expect, their behavior is unpredictable; they may run forever, or cause a system error.  In general, the user should only use "fast"  functions in code that has already been completely debugged, to speed it up.

{index destructive functions}

"Destructive" functions:  By convention, a function named by prefixing an existing function with {lisp D} indicates the new function is a "destructive" version of the old one, which does not make any new structure but cannibalizes its argument(s).  For example, {fn REMOVE} returns a copy of a list with a particular element removed, but {fn DREMOVE} actually changes the list structure of the list.  (Unfortunately, not all destructive functions follow this naming convention: the destructive version of {fn APPEND} is {fn NCONC}.)  The user should be careful when using destructive functions that they do not inadvertantly change data structures.


}{End SubSec "Fast" and "Destructive" Functions}



{Include Litatoms}

{Include Lists}

{Include Strings}

{Include Arrays}

{Include HashArrays}

{Include Numbers}




}{End Chapter Data Types}