5. Advanced Functions

The Input/Output Override Prefix Operators (& and @)

From outside the function, it is possible to store to the output or read from the input. It is generally considered bad form to do so, but is sometimes neccessary. This is done with the Input/Output Override prefix operators. The & operator forces use of the input queue, and the @ operator forces use of the output queue. When the & operator is used to store to the input queue (even if it would not be necessary) the function's code does not execute. Execution can then be forced later by storing a null queue to the function.

The Instruction Queue

Remember that a function consists of three queues? An input queue, an output queue, and an instruction queue? Well, the instruction queue isn't called a queue for nothing. You can manipulate it just like any other queue, as long as you use the instruction queue override prefix (~). Statments are enclosed in brackets [] to keep them as one item, but otherwise can be treated just like numbers (except that you can't do arithmetic with them, of course). The ability to manipulate the instruction queue can create very interesting self-modifying code. See Compound Data Types for examples of how this can be used.

The code Predefined Queue

There is another predefined queue, like in and out. It is code and it refers to the instruction queue of the current function, just as in and out refer to the input and output queues of a given function. In the main program, it refers to the main instruction queue.

Object Oriented Programming in Q-BAL

OOP (Object Oriented Programming) can be done in Q-BAL, but it is primitive compared to other languages such as C++. Then again, Q-BAL is not a object-oriented language, so it's surprising that you can do it at all. It's really a consequence of the capabilities of functions, and not a real designed capability of the language.

A function can act as an object. If it needs to store "member variables" it can do so in a static local variable (see above). The instruction queue can be set to do different things depending on how many arguments are put in the input queue at the same time (or even what type of argument: see variable data types, below), thus acting as different functions. Data can also be stored in the output queue. One function can be assigned to another of the same data type, replacing the target's instruction queue, input queue, and output queue.

Variable I/O and Functions

Since each function has its own in and out queues, it stands to reason that it would also have the corresponding variable I/O queues, and this is in fact the case. Each function has its own of all five variable I/O queues, and they function exactly the same as in the main program. Furthermore, if a function's ? queue is nonempty, then input to the device it specifies is considered input to the function and will cause execution of the instruction queue. In this way, Q-BAL can create an event-driven program. For this purpose, there is a stdin handle that can be stored to ?, even though the main program does not require it. Stdin can be accessed from a function through :in but this will not cause function execution. Also note that in order for this to work, the ? queue is static; that is, unchanged between function calls.

File Handling

File handling is done through variable I/O, but since the programmer needs to tell the computer what file to open before I/O is possible, it is handled through a function rather than a macro, and now that we know all about functions, we can cover it. FILE is a predefined function which takes as input a string which is the filename, with either a local or global path. If the filename does not exist, FILE will create it. It then returns a "file handle" which can be stored to ?, allowing I/O to that file. File I/O using FILE is sequential and appending. That is, if ?={filehandle}, then attachments from in? read one character at a time from the top of the file, sending an EOF when the file is over, and attachments to out? append characters to the end of the file. Assignments from in? read one line at a time, and assignments to out? write one line at a time (as is standard with I/O queues). There are also other miscellanous file-handling predefined functions such as FQ DELETE, which takes a queue of files to delete.

Static Local Variables

Functions can declare local variables, in the normal manner of variable declaration, but these variables do not keep their values when the function is called multiple times. Many functions can get around this by keeping values on the input or output queues, but sometimes this isn't sufficient, especially for OOP-like functions. One way to get around this is by declaring a queue outside the function that is only used from inside that function, but this is cumbersome.

The ? is Static

Each function has its own ? queue which remains unchanged from calling to calling, like a static variable. It is therefore possible to store single values in the ? queue between function callings, as long as the function does not utilize variable I/O. This is dangerous, however, because if the number stored happens to be the handle for some device, then the function may be inadvertently called by input to that device.

Dynamic Allocation

There is yet another area that variable I/O can handle: dynamic allocation of memory. C or C++ programmers will be familiar with this concept. To dynamically allocate memory for an object (of any data type), use the function F ALLOC. This function takes as input a string indicating the data type of the desired object (for example, "FQQ") and outputs a handle that can be stored to a ? queue. When this handle is on top of the ? queue, then the variable I/O queues access the dynamically created object. in? functions exactly like &x and out? exactly like @x, for an object named x. The queues 'in? and 'out? are not well defined when ? holds the handle of a dynamic variable. When a function dynamically creates variables, they are static because their handle (presumably in the ? queue) is also static. This is the best way for a function to create static variables.


Previous: Introduction to Functions
Next: Compound Data Types