REF IDENT                                           John Gibson May 1995

     COPYRIGHT University of Sussex 1995. All Rights Reserved.

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<                             >>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<         IDENTIFIERS         >>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<                             >>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

This REF file deals comprehensively  with all aspects of identifiers  in
Poplog; from their types to  their structure. Explanation is also  given
of their  dual-like  nature  with  words and  their  relation  to  undef
records.

         CONTENTS - (Use <ENTER> g to access required sections)

  1   Introduction
      1.1   Kinds of Identifiers
      1.2   Active Identifiers
      1.3   Weak Declarations for Permanent Identifiers

  2   Predicates On Identifiers

  3   Constructing Identifiers

  4   Accessing Information About Identifiers

  5   Manipulating Values of Identifiers

  6   Manipulating Attachment of Permanent Identifiers to Words

  7   Undef Records

  8   Miscellaneous

  9   Pop-11 Syntax For Use With Identifiers



---------------
1  Introduction
---------------

Identifier records are structures  that represent program variables  and
constants. In general, they contain the following information:

    #   A field for holding the value  of the identifier (its idval,  or
        valof when accessed via a word).

    #   Type information that restricts what  objects can be assigned to
        the identifier (its identtype).

    #   A flag saying whether  the identifier is  an active variable  or
        not, and if so, a field containing its multiplicity (see  Active
        Identifiers below).

    #   The  syntactic  properties  of  the  identifier  for  the Pop-11
        compiler, which tell the latter  how to interpret an  occurrence
        of the identifier name in a program (its identprops).

    #   An indication  of whether the identifier is lexical or permanent
        (see below).

Although identifier  records  can be  manipulated  in their  own  right,
program variables and constants are  always specified to compilers  (and
to the Poplog Virtual Machine) by name, i.e. by word records which  have
identifiers associated with them (see REF * WORDS).


1.1  Kinds of Identifiers
-------------------------
Identifiers used in a program (and declared to the Poplog VM) are of two
kinds: permanent (declared with vars or constant), and lexical (declared
with lvars or lconstant).  The latter are different  from the former  in
that their scope is not indefinite,  that is, a lexical identifier  only
exists while the file  or procedure that defines  it is being  compiled.
Permanent identifiers,  on the  other hand,  have indefinite  scope  and
exist until they are cancelled.

    For this  reason,  the  attachment  from  words  to  identifiers  is
maintained differently for the two  kinds. For lexical identifiers,  the
Poplog VM  holds an  association list  of words  to identifier  records,
entries being  deleted from  this list  when the  scopes of  identifiers
terminate. For  permanent identifiers,  the association  is achieved  by
making an  actual  field  in  the word  record  point  directly  to  the
identifier. (However,  a given  word can  be associated  with  different
permanent   identifiers    in    different   program    sections,    see
REF * SECTIONS.)

    Because of the duality  between words and  identifiers, some of  the
procedures described below can  take either an identifier  or a word  as
argument (this is indicated  by the argument name  wident as opposed  to
ident  for  an  identifier-only  argument).  However,  because   lexical
declarations exist only at  compile-time, these procedures when  given a
word argument will extract only  a PERMANENT identifier attached to  the
word. (The only way of accessing a lexical identifier associated  with a
word is via sys_current_ident, described in REF * VMCODE.)


1.2  Active Identifiers
-----------------------
Active identifiers  generalise  the  notion  of  a  identifier  with  an
associated value  by allowing  the actual  value slot  in an  identifier
record to contain not the associated value itself, but a procedure  that
will return that value when called. Thus, when an identifier is declared
active, attempting to access its value will cause the procedure found in
the value  slot to  be  executed, and  its result  returned.  Similarly,
attempting to  assign to  the  variable will  run  the updater  of  that
procedure with the new value passed as its argument.

    Moreover, the mechanism is generalised still further by allowing the
"nonactive"  procedure   and  its   updater  to   have  not   just   one
result/argument, but any fixed number of them: this number is called the
multiplicity of the active identifier. An access to an active identifier
of multiplicity M  therefore produces  M results, and  a similar  number
must be given when assigning to it.

    Various means  are provided  for  referencing the  actual  procedure
without  executing  it  (e.g.  nonactive_idval).  Note  that  an  active
identifier is  usually  a variable,  in  the sense  that  the  procedure
result(s) are  not  constant  (although the  nonactive  procedure  value
itself may be either constant or variable); however, it is also possible
to have an active constant, where the nonactive procedure does not  have
an updater (and the base procedure always returns the same value(s)).


1.3  Weak Declarations for Permanent Identifiers
------------------------------------------------
Permanent identifiers support a  weak mode of  declaration in which  the
identifier is not  considered to  have been fully  'defined' (in  Pop-11
this is represented by  the syntax weak constant  ... or weak vars  ...,
etc).

    The purpose  of  this  mode  is  to  enable  the  attachment  of  an
identifier record  to  a  word  record  so  that  its  section  context,
identprops and identtype, etc, are established,  but in a way that  does
not prevent operations  which access  the value of  the identifier  from
treating it as  if it were  still undefined (and  thus does not  prevent
autoloading of the value, for example).

    In particular (in  conjunction with  a Poplog VM  facility for  weak
references to identifiers  which does  not insist on  their being  fully
defined), it  allows programs  to  declare and  conditionally  reference
identifiers which may or may not be present at run-time. (This  includes
optionally-present protected  system  identifiers  for  which  a  normal
declaration would mishap, since weak declarations for identifiers  which
are already defined are simply ignored.)

    Another facility (available through the Poplog VM and via the Pop-11
syntax construct weakref) also allows the declared/defined status of one
identifier to be made dependent on a set of others, in the sense that if
any member of the dependency set becomes fully defined, then this forces
the dependent  identifier to  be defined  also (i.e.  as if  a  'strong'
reference to it had occurred).




----------------------------
2  Predicates On Identifiers
----------------------------

isident(item) -> kind                                        [procedure]
        Returns a true result if item is an identifier record, or  false
        if not. The true  result is a word  which indicates the kind  of
        identifier, as follows:

                 Word          Identifier Type
                 ----          ---------------
                "perm"         permanent identifier
                "lex"          'real' lexical identifier
                "lextoken"     'token' lexical identifier

        (The difference between "lex" and "lextoken" is that a "lex"  is
        a real  identifier record  whose idval  is its  actual  run-time
        value, whereas a "lextoken" is a record being used by the Poplog
        VM to represent  a procedure-local lexical  variable, and  which
        will not necessarily play  any part in  the final compiled  code
        for the procedure.)


isdeclared(wident) -> ident                                  [procedure]
        Given an identifier (of any  kind), this procedure just  returns
        its argument.  For wident  a word  with a  permanent  identifier
        currently  attached  the  (true)  result  is  that   identifier,
        otherwise false for an undeclared word. (The truth value of  the
        result is thus identical to identprops(wident) /== "undef".)

        This  procedure  differs  from  isdefined  in  that  it  returns
        identifiers which have only  weak declarations (see above).  (In
        fact, this is the only way  to access such an identifier  from a
        word, since identof will treat one as undefined.)


isdefined(wident) -> ident                                   [procedure]
        Same  as  isdeclared,  except  that  false  is  returned   for a
        permanent identifier  having  only  a  weak  declaration.  (Thus
        identprops(wident)  /==   "undef"   does  NOT   guarantee   that
        isdefined(wident) is true.)


isassignable(wident) -> bool                                 [procedure]
isconstant(wident)   -> bool                                 [procedure]
isprotected(wident)  -> bool                                 [procedure]
        These  predicates  test   extra  status   information  for   the
        identifier (or  permanent identifier  extracted from  the  word)
        wident:

        # isassignable returns true if wident can have its value updated
          (with idval etc, or a program assignment statement), false  if
          not.

        # isconstant returns a  true result if  wident is declared  as a
          constant, false if not. In the first case, the result is  true
          if a value  has been assigned  to the constant,  and the  word
          "undef"  otherwise  (note  that  isassignable  is  true  for a
          constant not yet assigned to).

        # isprotected returns  true if  wident  has been  declared  as a
          protected identifier, false if not.

        Note that by  default, these procedures  all return  information
        for the  active value  of  an active  identifier (if  an  active
        identifier has  no  updater,  then  isconstant  and  isprotected
        return true, and isassignable returns false).

        The status of the nonactive value can be got by wrapping  wident
        in a 'nonactive pair', i.e.

                conspair(wident, "nonactive")


isglobal(wident) -> bool                                     [procedure]
        Returns true  if  wident  is  declared  as  a  global  permanent
        identifier (that is, an  identifier which will be  automatically
        imported  into  daughter  sections   below  its  level),   false
        otherwise.


isactive(wident) -> mult_or_false                            [procedure]
        Given an identifier (or permanent identifier extracted from  the
        word) wident,  this  procedure  returns  a  true  value  if  the
        identifier is declared active, or false if not. The true  result
        returned is the active multiplicity  of the identifier, i.e.  an
        integer in the range 0-255.


isdlocal(wident, p) -> bool                                  [procedure]
        Given a  word  or identifier  wident  and a  procedure  p,  this
        procedure returns true if wident is  a dynamic local of p  (i.e.
        declared dlocal in p), or false otherwise.

        If wident  is an  active variable,  then by  default the  result
        reflects whether  its  active value  is  local; if  wident  is a
        variable active  variable,  and you  wish  to test  whether  its
        nonactive value is  local, wrap  wident in  a 'nonactive  pair',
        i.e.

                conspair(wident, "nonactive")




---------------------------
3  Constructing Identifiers
---------------------------

ident_declare(word, idprops, const_mode)                     [procedure]
        Declares  the  word  word   as  a  permanent   constant/variable
        identifier with identprops idprops in the current section.

        The const_mode argument is an integer in which bit 0  determines
        whether the  identifier  is  constant  or  variable,  and  bit 1
        whether this a weak  declaration or not  (for an explanation  of
        which, see Weak Declarations  for Permanent Identifiers  above).
        I.e.

            Bit      Meaning
            ---      -------
             0       0 = variable, 1 = constant
             1       0 = ordinary declaration, 1 = weak declaration

        Alternatively, const_mode  may  be  a boolean,  true  and  false
        representing constant/variable in ordinary  mode (i.e. 2:01  and
        2:00 respectively).

        Permissible values for the idprops argument are

            Value         Meaning
            -----         -------
            0             Untyped identifier.

            "procedure"   Procedure-type identifier.

            N             Pop-11 operation of precedence  N, where N  is
                          an integer  or  floating-point  in  the  range
                          -12.7 to 12.7 .

            "macro"       Pop-11 macro.

            "syntax"      Pop-11 syntax word.

            "syntax N"    Pop-11 syntax operator of precedence N,  range
                          as above.

        (Note that "syntax N" is not a normal itemisable word in Pop-11,
        and requires  additional  string  quotes  to  itemise  it,  e.g.
        "'syntax 3'" .)

        To declare an active variable, idprops may also be a pair  whose
        front is any of the above  identprops values, and whose back  is
        the  active  multiplicity.  For  an  ordinary  untyped  variable
        (identprops value 0), the multiplicity may be an integer in  the
        range 0  - 255;  for any  other identprops,  it must  be 1.  The
        const_mode argument  in this  case refers  to the  constancy  or
        otherwise of  the nonactive  procedure value  of the  identifier
        (its active value(s) are always variable).

        If word was previously  undeclared, the attached identifier  has
        its idval  initialised to  a  newly-created undef  record  whose
        undefword is word;  by default for  an existing identifier,  the
        idval is left undisturbed but the identprops etc are changed  to
        reflect the  new declaration  (except  for a  weak  declaration,
        which is ignored).

        Note that when a constant is declared, the Poplog VM effectively
        treats it as a variable until  a value is assigned to it  (after
        which, attempting to assign to it again produces a mishap); this
        means that 'forward' declarations and uses of constants in  code
        will actually  treat  the  identifier as  a  variable.  Also  by
        default,  the  same  applies   when  an  existing  constant   is
        redeclared (ensuring that recompiled  code does not continue  to
        use the  old value  of a  constant for  which a  new value  will
        recompiled later).

        However,   when   pop_debugging   is   false,   and   the   flag
        VM_PERM_FIXED_DECLARE  is  set   in  * pop_vm_flags,  then   any
        redeclaration for  an existing  identifier must  agree with  its
        current declaration (in  respect of  both constant/variable  and
        identprops), otherwise a mishap results. Moreover, in this  mode
        redeclarations of constants  do not reset  them to  'unassigned'
        (variable) status  (thus  permitting  a  file  in  a  multi-file
        program to  have header  declarations for  constants defined  in
        prior-loaded files,  without losing  the  benefit of  using  the
        constant values).

        Note also  that  when  pop_debugging has  the  value  true  (its
        default),  the  Poplog  VM  treats  all  user-defined  permanent
        constants as variables. See * pop_debugging.


consident(idprops, const_mode, kind) -> ident                [procedure]
        This procedure  gives  a  way to  construct  identifier  records
        directly, without the associated declaration of a word.

        The idprops argument specifies the identprops and/or  activeness
        of the identifier: permissible  values are as for  ident_declare
        above.

        The const_mode  argument is  also as  for ident_declare.

        kind specifies the  kind of  identifier as  returned by  isident
        (see above); permissible values are the words "perm", "lex"  and
        "lextoken".




------------------------------------------
4  Accessing Information About Identifiers
------------------------------------------

See also the is- predicates above for other properties of identifiers.


identprops(wident) -> idprops                                [procedure]
        Returns the identprops (macro/Pop-11  syntax properties) of  the
        identifier (or  permanent identifier  extracted from  the  word)
        wident. This can take the following values:

            Value         Meaning
            -----         -------
            "undef"       wident is a word  not declared as a  permanent
                          identifier  (i.e.  for  which  isdeclared   is
                          false).

            N             Pop-11 operation of precedence  N, where N  is
                          an integer  or  floating-point  in  the  range
                          -12.7 to 12.7 .

            "macro"       Pop-11 macro.

            "syntax"      Pop-11 syntax word.

            "syntax N"    Pop-11 syntax operator of precedence N,  range
                          as above.

            0             An "ordinary" permanent  identifier, i.e.  one
                          that has no special syntactic properties.

        (Note that "syntax N" is not a normal itemisable word in Pop-11,
        and requires  additional  string  quotes  to  itemise  it,  e.g.
        "'syntax 3'" .)


identtype(wident) -> type                                    [procedure]
        Returns the data type of the identifier (or permanent identifier
        extracted from the word) wident. Possible values are

            Value         Meaning
            -----         -------
            "undef"       wident is a word  not declared as a  permanent
                          identifier  (i.e.  for  which  isdeclared   is
                          false).

            0             Untyped, i.e. may hold anything.

            "procedure"   May hold procedures only.


full_identprops(wident) -> idprops_list                      [procedure]
        Returns  a  list  of  all  the  declaration  keywords  for   the
        identifier (or  permanent identifier  extracted from  the  word)
        wident, or  "undef"  if  wident  is a  word  not  declared  as a
        permanent identifier. The list has the form

            [prot  glob  const/var  type  idprops]

        where

            Value       Meaning
            -----       -------
            prot        "protected" for  a protected  identifier,  empty
                        otherwise;

            glob        "global"  for  a  global  permanent  identifier,
                        empty otherwise;

            const/var   "constant"   for   a   constant   (preceded   by
                        "assignable" if  the  identifier  can  still  be
                        assigned to), or "vars" for a variable;

            type        "procedure"  for  a  procedure-type  identifier,
                        empty otherwise;

            idprops     the identifier's identprops  (except that 0  for
                        an ordinary untyped  identifier is omitted,  and
                        "syntax N" for a syntax operator is returned  as
                        "syntax" followed by the number N).


is_syntax_word(item) -> idprops_or_false                     [procedure]
        If item is a  word whose identprops are  "syntax" or "syntax  N"
        then returns  those  identprops.  For any  other  item,  returns
        false.




-------------------------------------
5  Manipulating Values of Identifiers
-------------------------------------

See REF * PROCEDURE for more information  on dynamic local variables  of
procedures.


identof(word) -> ident                                       [procedure]
ident -> identof(word)
        Returns or updates the  permanent identifier currently  attached
        to word.

        In access  mode, if  word has  no permanent  identifier  already
        attached  (or   the  attached   identifier  has   only  a   weak
        declaration,  see  above),  sysdeclare  is  called  on  word  to
        autoload it or to provide a default definition (see REF * VMCODE
        for a description of sysdeclare).

        In  update  mode,  ident  must  be  permanent  identifier  (i.e.
        assigning a  lexical  identifier  is  not  allowed).  Note  that
        assigning an identifier to a dictionary word or a word  produced
        by  word_identifier   is  equivalent   to  declaring   it   with
        ident_declare, i.e. it  is registered by  the section  mechanism
        (see REF * SECTIONS).


idval(ident) -> item                                         [procedure]
item -> idval(ident)
        Returns or updates the  value cell of  the identifier ident  (in
        update mode, item must be valid for the identtype of ident).

        When ident  is  an active  variable,  idval runs  the  nonactive
        procedure value of  ident, or  its updater in  update mode.  The
        number of items produced as  results by the procedure, or  taken
        as arguments by its updater, will then be the multiplicity M  of
        the variable.


nonactive_idval(ident) -> item                               [procedure]
item -> nonactive_idval(ident)
        Returns or  updates  the value  cell  of the  identifier  ident,
        regardless of whether the identifier is active or not.


valof(wident) -> item                                       [procedure]
item -> valof(wident)
        Where wident  is an  identifier, or  a word  with an  associated
        permanent identifier,  returns  or  updates  the  idval  of  the
        identifier. That is, valof is the same as idval if wident is  an
        identifier, and otherwise the same as

                identof <> idval

        i.e. identof  is  first  applied  to  translate  a  word  to  an
        identifier.


nonactive_valof(wident) -> item                              [procedure]
item -> nonactive_valof(wident)
        Same as * valof, but using * nonactive_idval.


caller_valof(wident, caller) -> item                         [procedure]
item -> caller_valof(wident, caller)
        Where wident  is an  identifier, or  a word  with an  associated
        permanent identifier, returns or updates the valof of wident  as
        it would be in the environment of the currently-active procedure
        specified by caller.

        The argument caller may be either

         # An actual procedure  or a caller number as  input to * caller
           (see REF * PROCEDURE).

         # false,  meaning  that  the  value  outside  of  all   dynamic
           localisations  (i.e.   outside   all  procedure   calls)   is
           accessed/updated.

        (From Version 14.53, this procedure works correctly with  active
        variables, i.e. returns or updates their active value(s).)


nonactive_caller_valof(wident, caller) -> item               [procedure]
item -> nonactive_caller_valof(wident, caller)
        Same  as  * caller_valof,  but   active  variables  have   their
        nonactive value returned or updated.


set_global_valof(item, wident)                               [procedure]
        Using caller_valof, assigns item  to be the  value of wident  in
        the context of  every currently active  procedure for which  the
        identifier (or  permanent identifier  extracted from  the  word)
        wident is a dynamic local.


recursive_valof(word) -> item                                [procedure]
        Recursively applies  valof to  word while  item is  a word,  and
        returns the result -- that is, recursive_valof calls valof  with
        word  as  argument:  if  the   result  item  is  a  word,   then
        recursive_valof is called with item as argument; if it is  not a
        word, item itself is returned.




------------------------------------------------------------
6  Manipulating Attachment of Permanent Identifiers to Words
------------------------------------------------------------

syssynonym(word1, word2)                                     [procedure]
        An autoloadable library procedure, defined simply as

                identof(word2) -> identof(word1)


sysprotect(word)                                             [procedure]
        Protects the permanent identifier  associated with word --  that
        is, stops word being redeclared  (i.e. given a new  identifier),
        and disallows any assignment to the identifier.


sysunprotect(word)                                           [procedure]
        Unprotects the permanent identifier associated with word  (after
        a sysprotect) -- allows the word  to be redeclared (given a  new
        identifier), and makes possible assignment to the identifier.


syscancel(word)                                              [procedure]
        Cancels any permanent identifier currently attached to the  word
        word. This is registered by  the section mechanism if word  is a
        dictionary word  or  a  word produced  by  word_identifier  (for
        details see REF * SECTIONS).




----------------
7  Undef Records
----------------

Undef records  are  special records  containing  just one  field,  their
undefword, and  are used  by  the system  to  initialise the  values  of
newly-created  global  identifers  (although  they  be  used  for  other
purposes). The  undefword  may be  a  word  or false;  a  new  permanent
identifier is  initialised to  a  newly-constructed undef  record  whose
undefword is  the name  of the  identifier, whereas  new global  lexical
identifiers are initialised  to the fixed  undef record pop_undef  (with
undefword false, which prints as <undef>  as opposed to <undef foo>  for
one containing the word "foo").

However, since procedure-type identifiers  must always have a  procedure
value, they are initialised to  undef-closures, which are closures  of a
system error procedure, partially applied to the actual undef record for
the identifier (where  the error procedure  will produce an  appropriate
mishap if an  attempt is  made to  apply it).  Global lexical  procedure
identifiers use the standard undef-closure pop_undef_p.

Yet  another  type  of  undef-closure  is  used  to  initialise   active
variables: these are  such that  if the  variable is  accessed, it  will
return an actual undef  record M times, where  M is the multiplicity  of
the variable. Assigning to the variable  will simply erase M items  from
the stack.

All types  of  undef  record/closures  are  recognised  by  isundef  and
undefword. See also HELP * UNDEF.


isundef(item) -> bool                                        [procedure]
        Returns true  if item  is an  undef record  or an undef-closure,
        false if not.


consundef(word) -> undef                                     [procedure]
        Creates a new undef record  with undefword word, which may  be a
        word or false. For example:

            consundef("cat")=>
            ** <undef cat>


undefword(undef) -> word                                     [procedure]
        Returns a word or  false for the  undef record or  undef-closure
        undef.


pop_undef -> undef                                            [constant]
pop_undef_p -> undef                                         [procedure]
        The  standard  'untyped'   undef  record  and   'procedure-type'
        undef-closure (used  apart from  other things  for  initialising
        global lexical identifiers).

        (N.B.  The   constant   undef  should   really   be   pop_undef.
        Unfortunately, historically undef has always contained the  word
        "undef".)




----------------
8  Miscellaneous
----------------

_ -> undef                                                    [variable]
item -> _
        The 'anonymous'  (active)  variable  _  returns  pop_undef  when
        accessed, and discards any value assigned to it. For example,

                1, 2, 3 -> (x, _, y);

        will assign 3 to y, 1 to x, and discard the 2.

        This variable may also appear in Pop-11 identifier declarations,
        and as a formal argument or result in define headers, e.g.

                lvars (x, _, y) = dl([a b c]);

                define foo(arg1, _, arg3);
                    ...
                enddefine;

        (Uses of this  variable are  recognised and  fully optimised  by
        Poplog VM  instructions such  as sysPUSH,  sysPOP, sysLOCAL  and
        sysPASSIGN, etc.)


ident_key -> key                                              [constant]
undef_key -> key                                              [constant]
        Hold  the   keys  for   identifiers  and   undef  records   (see
        REF * KEYS).




-----------------------------------------
9  Pop-11 Syntax For Use With Identifiers
-----------------------------------------

ident                                                           [syntax]
        This syntax word compiles  code to push  an identifier onto  the
        stack (the identifier itself, not its value). Usage is

                ident name

        where name is  a word declared  as any kind  of identifier;  the
        effect is to push onto  the stack the (run-time) identifier  for
        the current declaration of name.

        (ident operates by calling  sysIDENT for the  given word --  see
        REF * VMCODE for more details.)

        Note that any ident expression for a permanent identifier may be
        surrounded by word quotes to  get the corresponding quoted  word
        identifier, e.g.

            "ident $-mysect$-xxxx" -> word_id;

        See REF * word_identifier for more details.


weak                                                            [syntax]
        Used  before  a  vars  or   constant  statement  to  make   weak
        declarations for permanent  identifiers (see `Weak  Declarations
        for Permanent Identifiers' above). E.g.

                weak vars foo, baz;
                weak constant xxx;


weakref                                                         [syntax]
        Flags a 'weak' access to  a permanent identifier, i.e. one  that
        will not  cause the  identifier  to become  'defined' if  it  is
        currently only weakly declared. In Pop-11

                weakref name

        can occur  anywhere where  name by  itself would  constitute  an
        identifier reference (i.e. excluding declarations). For example,

                weakref foo -> a;
                weakref foo(1,2,3);
                ident weakref foo -> id;
                nonop weakref foo -> p;
                dlocal weakref foo;

        etc. (In Poplog VM terms, weakref passes the identifier name  to
        the appropriate VM instruction inside a 'weakref pair', e.g.

                sysPUSH(conspair(name, "weakref"))

        See REF * VMCODE.)

        weakref has also has  a more complicated  form which allows  the
        declared/defined status of one  identifier to be made  dependent
        on a set of others. The syntax

                weakref [ dname1, dname2, ..., dnameN ] name

        is identical in terms of code produced to

                weakref name

        but  additionally  declares  name  as  being  dependent  on  the
        identifiers dname1  ... dnameN.  This  means that  whenever  any
        member of the  dependency set becomes  fully defined  (including
        the case where one  or more already are),  then this forces  the
        dependent identifier name to be  defined also (as if a  'strong'
        reference to it had occurred). E.g.

                weakref[foo, baz] grum()

        makes grum dependent on  the status of  foo and baz.  Dependency
        identifiers for  a given  identifier accumulate  across uses  of
        weakref, so that a later

                weakref[xxx] grum()

        will make grum dependent on all of foo, baz and xxx.


testdef                                                         [syntax]
        Allows the declared/defined status of a permanent identifier  to
        be tested. The form

                testdef name

        is equivalent to the truth value of the expression

                isdefined(ident weakref name)

        Since  a  weakly  declared   identifier  has  an  undef   value,
        attempting to execute it as in

                weakref foo(1,2,3);

        may cause a mishap; weak references should therefore normally be
        protected with testdef used in a conditional, e.g.

                if testdef foo then
                    weakref foo(1,2,3)
                endif;

        guarantees that foo will be  executed only if fully defined.  On
        the other hand, uses such as

                if value == weakref foo then ...

        are safe without a testdef (assuming that value can never be the
        undef value of foo). In particular,

                dlocal weakref foo;

        is always safe.


cancel                                                          [syntax]
        Cancels permanent identifiers. Usage is

            cancel name1, name2, ..., nameN ;

        where each  name  is an  identifier  name (which  can  include a
        section pathname). It applies syscancel  to each name (but  note
        that it will not cancel protected identifiers -- if you want  to
        do this,  either use  sysunprotect  on the  word first,  or  use
        syscancel directly).



--- C.all/ref/ident
--- Copyright University of Sussex 1995. All rights reserved.
