[top] [prev] [next]

Unsafe operations

There are some cases that no law can be framed to cover. ---Aristotle

The features defined in this section can potentially cause unchecked runtime errors and are thus forbidden in safe interfaces and modules.

An unchecked type transfer operation has the form:

    LOOPHOLE(e, T)
where e is an expression whose type is not an open array type and T is a type. It denotes e's bit pattern interpreted as a variable or value of type T. It is a designator if e is, and is writable if e is. An unchecked runtime error can occur if e's bit pattern is not a legal T, or if e is a designator and some legal bit pattern for T is not legal for e.

If T is not an open array type, BITSIZE(e) must equal BITSIZE(T). If T is an open array type, its element type must not be an open array type, and e's bit pattern is interpreted as an array whose length is BITSIZE(e) divided by BITSIZE(the element type of T). The division must come out even.

The following operations are primarily used for address arithmetic:

               ADR  (VAR x: Any)            : ADDRESS 

     infix     +    (x: ADDRESS, y:INTEGER) : ADDRESS
     infix     -    (x: ADDRESS, y:INTEGER) : ADDRESS
     infix     -    (x,y: ADDRESS)          : INTEGER
ADR(x) is the address of the variable x. The actual argument must be a designator but need not be writable. The operations + and - treat addresses as integers. The validity of the addresses produced by these operations is implementation-dependent. For example, the address of a variable in a local procedure frame is probably valid only for the duration of the call. The address of the referent of a traced reference is probably valid only as long as traced references prevent it from being collected (and not even that long if the implementation uses a compacting collector).

In unsafe modules the INC and DEC statements apply to addresses as well as ordinals:

               INC  (VAR x: ADDRESS; n: INTEGER := 1)
               DEC  (VAR x: ADDRESS; n: INTEGER := 1)
These are short for x := x + n and x := x - n, except that x is evaluated only once.

A DISPOSE statement has the form:

               DISPOSE (v)
where v is a writable designator whose type is not REFANY, ADDRESS, or NULL. If v is untraced, the statement frees the storage for v's referent and sets v to NIL. Freeing storage to which active references remain is an unchecked runtime error. If v is traced, the statement is equivalent to v := NIL. If v is NIL, the statement is a no-op.

In unsafe interfaces and modules the definition of "assignable" for types is extended: two reference types T and U are assignable if T <: U or U <: T. The only effect of this change is to allow a value of type ADDRESS to be assigned to a variable of type UNTRACED REF T. It is an unchecked runtime error if the value does not address a variable of type T.

In unsafe interfaces and modules the type constructor UNTRACED REF T is allowed for traced as well as untraced T, and the fields of untraced objects can be traced. If u is an untraced reference to a traced variable t, then the validity of the traced references in t is implementation-dependent, since the garbage collector probably will not trace them through u.

[top] [prev] [next]