Intrinsic Procedures and Methods

Intrinsic Procedures

An OADL intrinsic procedure is one which is built-in to the OADL machine. It is not possible to place the address of an intrinsic procedure in a variable. Additionally, the number of arguments to intrinsic procedures is generally checked at compile-time. All OADL intrinsic procedures except for typeof are found in the oadl namespace.

Procedure Argument Intrinsic Procedures

These intrinsics deal with procedure arguments:

arg(n)
Returns the value of argument number n
nargs()
Returns the number of arguments passed to the current procedure.
argvec()
Returns a List containing all of the arguments to the current procedure.


Machine Execution Intrinsic Procedures

These intrinsics modify the execution of the OADL machine:

halt()
Immediately halts execution of the OADL virtual machine.
setjmp(arr)
Sets the target for a later longjmp() non-local jump
longjmp(arr, val)
Does a non-local jump to an enclosing procedure location where setjmp() was called
save(filename)
Saves the complete OADL state to a file
restore(filename)
Restores the complete OADL state from a file
restart()
Restarts the entire OADL machine


Memory Subsystem Intrinsic Procedures

These intrinsics manage various aspects of the dynamic memory subsystem:

gc()
Immediately performs a garbage collection cycle
protect(val)
Returns a new read-only copy of a value
readonly(val)
readonly(obj, pub)
Checks to see if a value is read-only
deleted(obj)
Returns true if the given obj has been marked for deletion
perm(val)
Creates a "permanent" copy of the given value
transient(val)
Check whether the given value is located in the default, dynamic memory pool


Type Checking Intrinsic Procedures

These intrinsics return information about the types of their arguments:

typeof(val)
Returns the type of a value; for example, Int, Null, Float, etc. Unlike all other intrinsic procedures, typeof() is found in the global namespace.
typecheck(typ, val)
Checks to ensure that the type of val is derived from typ. If not, a TypeCheck exception is thrown. Returns true if the type matches.
is_a(obj,cls)
Returns true if the class cls is a parent of the given object obj, and false otherwise. Same as the ?= comparison operator.

Input / Output Intrinsic Procedures

These procedures are all found in the global namespace. See the chapter on Input / Output for more information about them.

getchar()
getchar(file)
Get a single character of input
print(fmtstring, arg, ...)
print(file, fmtstring, arg, ...)
Print a formatted set of values
putchar(ch)
putchar(file, ch)
Puts a single character to a file
ungetc(ch)
ungetc(file, ch)
Returns a single character to a file's input buffer
read(fmtstring, typ, ...)
read(file, fmtstring, typ, ...)
read(string, fmtstring, typ, ...)
Reads a formatted set of values
readstr()
readstr(file)
Reads a string from a file
say(arg, arg, ...)
say(file, arg, arg, ...)
Prints a list of values with default formatting rules


Other Intrinsic Procedures

There are a couple of other miscellaneous intrinsic procedures supported by OADL:

matchvec()
Returns a List of all of the match pattern substrings ?1, ?2, etc.
format(fmtstring, arg, ...)
Create a string representation of the arg list given the format specifier fmtstring.

Standard Class Methods

Several methods are predefined for all OADL classes. They may be overridden by the OADL programmer. See the chapter on Classes for a detailed description of these methods:

obj.create()
Called when a new static or dynamic Object is created
obj.destroy()
Called if an object is to be destroyed during dynamic memory reclamation
obj.operator {}(args)
Object completion operator


Intrinsic Methods

Intrinsic methods are provided by OADL to perform a broad range of operations. Note that, unlike programmer-defined methods, OADL intrinsic methods can operate on values with types other than Object.

Type Query Intrinsic Methods

arr.arrbase()
Returns the base type of arr (for example, Char, Int, etc.) or Array if arr is a heterogeneous List or Array.
val.isarray()
Returns true if val is an array of any kind (List, String, PackInt, etc.) and false otherwise.
val.ischar()
Returns true if val is a scalar character of any kind (Char or WideChar) and false otherwise.
val.isfloat()
Returns true if val is a floating point scalar of any kind (Half, Float, or Double) and false otherwise.
val.isinteger()
Returns true if val is an integral scalar of any kind (Byte, Ubyte, Short, Ushort, Int, Uint, Long, or Ulong) and false otherwise.
val.isnumeric()
Returns true if val is a numeric scalar of any kind (Byte, Ubyte, Short, Ushort, Int, Uint, Long, Ulong, Half, Float, or Double) and false otherwise.
val.isstring()
Returns true if val is string of any kind (String or WideString) and false otherwise.
val.length()
Returns the number of elements along the first dimesion of an array, or the number of public properties of an object, or the number of currently defined key/value pairs in a dictionary.
typ.maxval()
Returns the maximum possible value of the given typ (Float, Int, etc.)
typ.minval()
Returns the minimum possible value of the given typ (Float, Int, etc.)
typ.packtype()
Returns the packed array type that corresponds to the scalar type typ (for example, Int.packtype() returns PackInt)
val0.promote(val1)
Returns the entry in the type promotion table from the Expressions chapter that corresponds to val0 and val1. If val0 or val1 is an OADL Type they are used directly. If they are not an OADL TYpe, their base types are used as the indexes into the table.
val.rank()
Returns the rank of val - the number of dimensions of the given array. The rank of a scalar is 0.
val.shape()
Returns a PackInt array which is the multi-dimensional shape of val. The shape of a scalar is the empty packed integer array 0->iterate()
val.sizeof()
Returns the total number of elements of array or dictionary val. The sizeof a scalar is 1.

Dynamic Value Management Intrinsic Methods

val.copy()
Creates a copy of the given array, string, or object. The elements of an array are NOT recursively copied. This is identical in effect to the @ operator. The new copy is neither permanent nor read-only regardless of whether val is permanent or read-only.
val.deepcopy()
Creates a copy of the given array, string, or object. The elements of an array ARE recursively copied. This is identical in effect to the @@ operator. The new copy is neither permanent nor read-only regardless of whether val is permanent or read-only.
val.readonly()
obj.readonly(pub)
The zero-argument form returns whether the given object or array value val is read-only. The one-argument form returns whether the public property pub of Object obj is read-only. A TypeCheck exception is thrown if val, obj, or pub is not of an appropriate type.
val.transient()
Returns true if the given val is located in dynamically maintained memory subject to garbage collection, and false otherwise. A TypeCheck exception is thrown if val is not of an appropriate type.

File Input / Output Intrinsic Methods

See the chapter on Input / Output for more information about these intrinsic methods.

file.binary()
Query whether a file was opened in binary-mode
file.clearerr()
Clear a file's error indicator
file.close()
file.close(disp)
Close a file
file.feof()
Query a file's end-of-file indicator
file.ferror()
Query a file's error indicator
file.fflush()
Flush pending output
file.fseek(offs, whence)
Change a file's read/write position
file.ftell()
Query a file's read/write position
file.getchar()
Read a single byte from a file
file.getswab()
Query a file's byte-swap indicator
file.ispipe()
Query whether a file is a pipe
file.print(fmtstr, arg, ...)
Print formatted values
file.putchar()
Put a byte into a file
file.read(typ, typ, ...)
file.read(fmtstr, typ, typ, ...)
string.read(fmtstr, typ, typ, ...)
Read values from a file
file.readonly()
Query whether a file was opened read-only
file.readstr()
Read a string from a file
file.rewind()
Move a file's read/write position to the beginning
file.say(arg, arg, ...)
Print values with default formats
file.setswab(bSwab)
Set a file's byte-swap flag
file.ungetc()
Push back a byte to a file's input stream
file.write(val, val, ...)
Write binary values to a file

Mathematical Intrinsic Methods

val.abs()
Computes the absolute value of val
val.clamp(lower, upper)
Compares val to the given lower and upper bounds, clamping it to those bounds and returning the new value.
val.fix2flt(typ)
Convert a value or array of values from 8- or 16-bit signed or unsigned integers to the specified floating point type
val.flt2fix(typ)
The inverse of fix2flt(). Convert a value or array of values from floating point to a specified 8- or 16-bit signed or unsigned fixed-point number.
val.lerp(lower, upper)
Linearly interpolates or extrapolates from given lower and upper bounds. If val is less than zero, it extrapolates below lower. If val is greater than one, it extrapolates above upper. Otherwise, it interpolates between lower and upper, returning the interpolated values. The interpolator val must be of a floating-point type. Appropriate type conversions are performed on the interpolants lower and upper.
val0.max(val1, val2, ...)
Computes the maximum of a set of values. Appropriate type conversions are performed between the values.
val0.min(val1, val2, ...)
Computes the minimum of a set of values. Appropriate type conversions are performed between the values.
val0.satadd(val1, lower, upper)
Computes val0 plus val1 and clamps the result to the given lower and upper bounds. Appropriate type conversions are performed between the values and the bounds.
val0.satsub(val1, lower, upper)
Computes val0 minus val1 and clamps the result to the given lower and upper bounds. Appropriate type conversions are performed between the values and the bounds.
val.signum()
Computes the signum of val, which is defined as -1 if val is less than minus zero, 1 if val is greater than zero, or 0 if val is equal to zero. The return type is the same type as that of val.

Array Manipulation Intrinsic Methods

Many of these methods were inspired by the programming language APL, which is an innovative interactive language developed in the 1960s to perform many array calculations and general-purpose computing tasks. There are a few conventions that should be noted:

Unlike APL, English names of the various array operations are used for the array intrinsic methods.

arr.accum(op)
arr.accum(op, axis)
Accumulate results of an operation across an axis. Similar to APL op \ arr and op \[axis] arr.
arr0.arrcmp(arr1)
Lexicographically compares two arrays or strings, returning -1, 0, or 1
a.concat(b, c, ...)
Concatenates several values, returning a new array or string. Exactly the same as the ## operator.
val0.decode(val1)
Convert non-uniform number bases, evaluate polynomials. Similar to APL val0 val1
arr.disclose()
Remove a level of nesting from an enclosure. Similar to APL val
arr.drop(num)
arr.drop(num, axis)
Similar to APL num arr and num ↓[axis] arr
val.enclose()
val.enclose(axis)
Enclose a value to make a scalar. Similar to APL val or ⊂[axis] val.
val0.encode(val1)
Similar to APL val0 val1
arr.flatten()
Completely flattens an array, including any nested elements
vec.increment(shp)
No direct APL comparison. Given a vector vec of the same length as vector shp (which is the shape of a multidimensional array), compute what the next vector index in row-major order would be. Returns nil if the next multi-dimensional index would step past the array bounds. This is useful with the "flattened" indexing operator, especially in combination with the arr.stride() intrinsic method:
    arr = "abcdef".reshape(2,3)
    arr
abc
def
    shp = arr.shape()
    idx = (0).reshape(arr.rank()) // Start with [0,0]
    strd = arr.stride()           // Needed to compute offset
    do {
        var n = idx.inner(`+,`*,strd); // Sum of products of idx and stride
        "arr[", idx, "] == ", arr#[n], '\n'; // Note: flattened index operator
        idx = idx.increment(shp); // Increment to next index in shape
    } while (idx != nil)
arr[0 0] == a
arr[0 1] == b
arr[0 2] == c
arr[1 0] == d
arr[1 1] == e
arr[1 2] == f
arr0.inner(op0, op1, arr1)
Similar to APL arr0 op0 . op1 arr1. The inner product is probably the most difficult operation to fully explain. In the simple case of two vectors, it is equivalent to:

(vec0 op1 vec1).reduce(op0)

In APL notation, the operation is defined as:

op0/¨(⊂[⍴⍴arr0]arr0)∘.op1⊂[1]arr1

Anybody who finds this definition helpful is already an APL expert and does not need the inner product explained further. However, a more readable algorithm is:
    // Enclose arr0 along the last axis
    var encl0 = arr0.enclose(-1);

    // Enclose arr1 along the first axis
    var encl1 = arr1.enclose(0);

    // Compute outer product of enclosed arrays with second operator
    var out = encl0.outer(op1,encl1);

    // For each element in the outer product, reduce it by the first operator
    var result = new Array(out.shape());
    forall (out#[i]) result#[i] = out#[i].disclose().reduce(op0);

    // Pack the result
    result = result.pack();

    // Convert single-element vector to scalar
    if (result.sizeof() == 1) result = result#[0];
vec.intersect(arr)
Similar to APL vec arr
val.iterate()
Creates a new multi-dimensional PackInt array with a shape of val, initialized to the numbers from 0 to n-1 inclusive, where n is the product of all of the elements of val. Note that val may also be a scalar; in this case, care must be taken to prevent OADL from interpreting the dot operator as part of a floating point constant. The normal convention is to place parentheses around the scalar in this case; e.g. (3).iterate().
arr0.laminate(arr1)
arr0.laminate(arr1, axis)
Similar to APL arr0 , arr1 and arr0 ,[axis] arr1
val.member(arr)
Similar to APL val arr
arr.nreduce(n, op)
arr.nreduce(n, op, axis)
Similar to APL n op / arr and n op /[axis] arr. The nreduce() method inserts the given operator op between each element of each n-long subset of the array, along the specified axis. Note that the result is evaluated right-to-left. This may be changed to right-to-left order by specifying a negative n. The resulting array has the same rank as the original array, but its size along the specified axis will be reduced by n-1.
    a = {"a", "b", "c", "d", "e", "f", "g"}
    a.nreduce(3, `##)
abc bcd cde def efg

    arr.nreduce(-3,`##)
cba dcb edc fed gef
arr0.outer(op, arr1)
Similar to APL arr0 ∘. op arr1. The outer product takes corresponding elements from arr0 and arr1 and applies op to them. For vectors, this produces an operator table:
    x = [2,3,4]
    y = [1,2,3,4]
    x.outer(`*, y)
2 4  6  8
3 6  9 12
4 8 12 16

More generally, the destination array has a shape which is the concatenation of the shapes of arr0 and arr1. Each element of the destination array is assigned thus:

result[i00, i01, ..., i10, i11, ...] = arr0[i00, i01, ...] op arr1[i10, i11, ...]

arr.pack()
Attempt to create a new packed copy of the given array. Will always create a new array; however, arrays which are not packable will, obviously, not be packed.
vec.position(val)
Similar to APL vec val
arr.ravel()
arr.ravel(axis)
Similar to APL , arr and ,[axis] arr
arr.reduce(op)
arr.reduce(op, axis)
Similar to APL op / arr and op /[axis] arr. The reduce() method inserts the given operator op between each element of the array, along the specified axis. Note that the result is evaluated right-to-left. This is for consistency with APL. For example:
    arr=(10).iterate()
    arr.reduce(`-)
-5
    // Left-to-right reduce evaluation
    0-1-2-3-4-5-6-7-8-9
-45
    // Right-to-left reduce evaluation - per APL and OADL
    0-(1-(2-(3-(4-(5-(6-(7-(8-9))))))))
-5
arr.replicate(key)
arr.replicate(key, axis)
Similar to APL key / arr and key /[axis] arr and also similar to APL key \ arr and key
val.reshape(d0, d1, ...)
val.reshape(shp)
Creates a reshaped copy of the array or dictionary or scalar val specifying that the new array or dict will have a shape of [d0, d1, ...]. Note that the single-argument form can specificy a single-dimensional PackInt which will be the shape of the new array. Dictionaries may not be made smaller, only larger. Returns the new resized copy of val.
arr.reverse()
arr.reverse(axis)
Similar to APL arr and ⌽[axis] arr. Reverses the order of elements along the given axis. For example:
    a = [2,3].iterate()
    a.reverse()
2 1 0
5 4 3
    a.reverse(0)
3 4 5
0 1 2
arr.rotate(num)
arr.rotate(num, axis)
Similar to APL num arr and num ⌽[axis] arr. Rotates the elements of an array along the given axis by the given number of places. For example:
    arr = [4,4].iterate()
    // Rotate arr by 1 place along last axis
    arr.rotate(1)
 3  0  1  2
 7  4  5  6
11  8  9 10
15 12 13 14
    // Rotate arr by 2 places along last axis
    arr.rotate(2)
 2  3  0  1
 6  7  4  5
10 11  8  9
14 15 12 13
    // Rotate arr by 1 place along first axis
    arr.rotate(1,0)
12 13 14 15
 0  1  2  3
 4  5  6  7
 8  9 10 11
arr.sort()
arr.sort(cmp)
Returns a sorted copy of arr according to the optional cmp proc or operator. If cmp is not specified, operator < is assumed.
arr.stride()
No direct APL comparison. Returns a vector that indicates the number of elements between corresponding elements of the same axis of the source array. This is useful with the "flattened" indexing operator #[].
arr.subr(beg0, end0, beg1, end1, ... )
Returns the multi-dimensional substring or subarray from the given array starting at index beg0, beg1, ... up to and including index end0, end1, .... The data used by this substring or subarray is NOT part of the original string or array; therefore, modifying its contents will not modify the original object. If begn is nil the subrange starts at the beginning of that particular dimension. If endn is nil, then the subrange goes to the end of that particular dimension. If arr is not an array, or if any begn or endn is not an integer (or nil) then the TypeCheck exception is thrown. The subrange is clamped to the actual bounds of the array or string. If endn is less than begn the result is an empty array or string. This is closely related to the use of : in array indices.
arr.take(num)
arr.take(num, axis)
Similar to APL num arr and num ↑[axis] arr
arr.transpose()
arr.transpose(code)
Similar to APL arr and code arr. If no code is given, reverses the order of axes of an array. The code is a vector containing instructions on the order of axes. The length of the code must be the same as the rank of arr. Each element of the code is an axis from arr. If each element of code is unique, it simply specifies a new order for the result axes. If an element in code is repeated, then axes of the array are mapped together and the rank of the result will be less than the original array. Additionally, the maximum axis allowed to be present in code is reduced. If the axes that are mapped together are of different lengths, the shorter axis controls the number of elements for the destination array along that axis. In effect, repeated axes traverse a diagonal of the original array For example:
    arr = [2,3].iterate()
    arr.transpose()
0 3
1 4
2 5
    // 2 slabs of 3 rows by 4 columns
    arr = [2,3,4].iterate()
    arr
 0  1  2  3
 4  5  6  7
 8  9 10 11

12 13 14 15
16 17 18 19
20 21 22 23
    // Orig. axis 0 goes to new axis 1 (old slabs -> new rows)
    // Orig. axis 1 goes to new axis 0 (old rows -> new slabs)
    // Orig. axis 2 goes to new axis 2 (old cols -> new cols; NOP)
    arr.transpose([1,0,2])
 0  1  2  3
12 13 14 15

 4  5  6  7
16 17 18 19

 8  9 10 11
20 21 22 23
    // Orig. axis 0 goes to new axis 1 (old slabs -> new rows)
    // Orig. axis 1 goes to new axis 0 (old rows -> new slabs)
    // Orig. axis 2 ALSO goes to new axis 1 (old cols -> new rows ALSO)
    //    (The shorter of axis 0 and axis 2 is axis 0. The new
    //    columns are taken from arr[0,x,0] and arr[1,x,1])
    arr.transpose([1,0,1])
0 13
4 17
8 21
vec.union(arr)
Similar to APL vec arr
vec.unique()
Similar to APL vec
arr.unpack()
Create a new unpacked copy of the given array, resulting in either a List (for single-dimensional arrays) or an Array (for multi-dimensional arrays).
val.width()
Returns the number of elements along the last dimesion of an array
vec.without(arr)
Similar to APL vec ~ arr

Back to Procedures

Continue to External Procedures

Return to Introduction