The keyword "extern" has two distinct uses. 1) It may be used to introduce references to non-Russell functions. A function construction may have the form func[param_list; var Void]result_sig { extern "extern_func_name" } Applying a function constructed in this way will result in a call to the non-Russell function with the indicated name. The external function should either reside in the standard C library, or should be explicitly linked to the compiled Russell program. The external procedure name must be complete, that is, it should usually start with an underscore character. Restrictions apply to C routines called in this way. The main ones are: a) They do not have to be pure functions, since they are forced to take a var Void parameter. They should however respect the parameter and result signatures. It is useful to note that val ChStr ~ char * val Short ~ long (short in the Vax implementation) val Float ~ double * Variables are usually represented as a pointer to a one word cell containing the actual value. (Float variables have the same representation as values.) Arrays are pointers to blocks of storage, the first word of which contains the number of elements in the array. The var Void parameter is not actually passed (except by the Vax code generator). It should be ignored. b) Any references to malloc will get linked to standard malloc (except for the old Vax code generator, where life is much more complicated). This means that objects allocated this way should not contain references to Russell objects, as such references will be hidden to the garbage collector. Use gc_malloc if you want references to be found. 2) A separately compiled Russell expression is denoted by extern { "file_name" } It is assumed that object code for the expression resides in file_name.o in the current directory, and that its entry point was built from the specified file name. It is also assumed that signature (and optimization) information is attached to the end of the file. (I.e. it is assumed that the file was produced with "rc -c" and was moved to the current directory.) The compiler will automatically link the ".o" file to the compiler output. (This is suppressed if the -c option is specified. Nested references to separately compiled expressions currently require manual linking.) If stack.o contains a separately compiled implementation of stacks, (e.g. stack.r might contain a function construction, which given a type argument T, produces the type of stacks of T) it can be bound to the identifier "stack" with the following declaration: let stack == extern { "stack" } in ... ni Implementation note: Calls to C functions are slightly less efficient than from C, but not much. Separately compiling Russell functions currently does not result in a major loss of efficiency. In particular, tiny separately compiled functions may still be expanded in-line, and slightly bigger ones may still be called using a stream-lined calling convention. On the negative side, even separately compiled functions are not guaranteed to show up on adb stack traces.