OOF – A New Programming Metaphor

NEW PROGRAMMING METAPHOR

The “OOF” or “Object-Oriented Fail” family of languages is intended to deliver reliable, deterministic, 100% failure rates to public institutions seeking to implement social programs to increase nationwide stress, eliminate all disposable income of and decrease the average quality-of-life for all members of the middle class.

INHERITANCE MODEL

In the past, OO languages have been forced to choose between single- and multiple-inheritance models. OOF languages, however, dispense with this model by introducing the concept of “half inheritance”: derived classes will inherit precisely half of the properties of their base classes, selected by a pseudorandom number generator at runtime. This ensures that no defined class can be represented as a directed acyclic graph or UML model. By choosing the revolutionary half-inheritance model, all “design-up-front” development methodologies will be rendered instantly obsolete.

MEMORY MANAGEMENT

Instead of employing memory management, OOF languages must, in the initialization routine of the garbage injector, use operating system calls to allocate and pre-initialize the largest block of free heap available. Access to objects and variables must be aligned on “n”-byte boundaries, where “n” represents the current day of the month. This will provide consistency in the number of available variables and/or objects in a given program on a given day. Programmers should take care to design their usage of variables and objects with the lowest day-number of any given month in mind. All access to heap memory is through pointers in the code segment, which are to be managed by the garbage injector.

GARBAGE INJECTOR

The garbage injector’s prime responsibility is to modify the addresses of all such aforementioned pointers using the same runtime pseudorandom number generator as used by the half-inheritance system. Data pointed to will be copied from its original location to its new location in ascending order. No mechanism is provided to examine the usage of the new location prior to overwriting its data with the result of the pending copy operation. This mandatory operation will run during idle CPU cycles, and result in a consistently inconsistent execution environment for all system and user programs.

GARBAGE COLLECTOR

The garbage collector will address the inconsistencies of the OOF program’s execution environment, as ensured by the garbage injector. Its operation is simple: any access to variables or objects will trigger a call into system BIOS routines which will reboot the entire computer, thus eliminating any inconsistencies in the program’s state, and indeed, the program’s ability to store and retrieve state at all.

IMPLEMENTATION GUIDELINES

We recommend that the runtime library for any OOF language be web-enabled in such a manner as to crash or otherwise disable the end user’s web user agent when any request is made for an OOF program or subroutine. Ideally, this disabling mechanism should also initiate a low-level format of the user’s fixed storage devices. It is recommended that any government implementation of an OOF system be paired with extensive subsidies for large computer repair establishments, such as The Geek Squad. This will provide  maximal economic benefit to all.

Advertisements

Using GT.M external calls to access shared libraries

Many times, when developing MUMPS applications, you may come upon a situation where you need to use a bit of functionality exposed by a Linux shared library. FIS GT.M provides support for this via its external call mechanism. The syntax and semantics are a bit odd, so we’ll step through the implementation of a wrapper for some of the  trigonometry functions exposed by the C standard library. This example will be produced with the intention of being complete and usable.

Assumptions on the Reader

I will assume that you have a reasonably recent GT.M release configured on a Linux system. I will assume that you have access to a bash shell prompt (for those of you using VistA, a captive account which takes you directly into a VistA entry point is not sufficient for this tutorial, as you will be creating several files in the Linux filesystem with tools which don’t exist in or are inaccessible from the GT.M programmer mode. If this applies to you, please see your local guru for help).

I will assume that your local GT.M routines are in $HOME/p, that $gtmroutines is set accordingly, that you have a $HOME/lib directory available, and that your GT.M environment is set up to the point where you can read and set MUMPS globals.

I will also assume that you have working knowledge of MUMPS and C programming, including basic knowledge of pointers and their use for the latter language.

I will also assume that you have gcc and make installed, and that you or your system manager has made them available in your search path. If you are working through this example on your own machine, here are some instructions for getting gcc and make running:

Ubuntu

$ sudo apt-get install build-essential

Other Distributions

For other distributions, please search Google.
First, let’s talk a bit about the overall architecture of the GT.M external call mechanism.

Architecture

The GT.M external call mechanism uses a layered architecture. The GT.M runtime looks in the GTMXC_yourcalltable environment variable to find the location of a .xc file which contains the GT.M to C mappings. The .xc file also contains a path to a shared library (a file ending with the .so extension) in which the external routines are defined. Here’s an abstract overview of what the architecture looks like:

GT.M Callout Architecture

Figure 1.1: Abstract GT.M external call architecture

If we were creating new functionality without trying to access an existing shared library, the wrapper_library.so and wrapped_library.so pieces of the stack would likely be replaced with a single .so file containing the new functionality.

In this case, we’ll derive from this abstract architecture a more concrete architecture to apply to our trigonometry wrapper:

Concrete Architecture

Figure 1.2: Concrete architecture for our applicaton

GT.M Type System

When working with external calls to non-MUMPS shared libraries in GT.M, you need to first come to terms with the fact that you are going to end up writing C wrapper functions for every function you use. Unfortunately, GT.M lacks the intelligence to directly call external functions of arbitrary types and parameter lists, and requires an external call table to map the weakly-typed data of C to the untyped data of MUMPS.

Return Values

In order for an external function to be callable by GT.M, it can only return one of three types:

  • gtm_long_t (a long integer)
  • gtm_status_t (an int)
  • void (function does not return a value)

For our purposes, we will use gtm_status_t for as the return values’ types. This will allow us to return a 0 value from our wrapper functions when successful. Returning a nonzero value will indicate to GT.M that an error has occurred. For the sake of clarity, we will leave extensive error handling as an exercise to the reader.

Parameters

Each parameter can be either an input parameter (GT.M passes the value of this parameter to C) or an output parameter (GT.M passes a reference to this parameter to C, which populates it with a return value). Parameters can be any of the types listed in Chapter 11 of the GT.M UNIX Programmer’s Guide. For our purposes, we will be using gtm_double_t* for both our input parameters and output parameters.

External Call Table

Okay, we’re now ready to look at the format of the external call table (trig.xc in our example). The first line must be a full UNIX path to the shared library that GT.M will call, for example:

$HOME/lib/trig.so

This will tell GT.M to look in /home/your_username/lib/trig.so when trying to resolve the functions defined within the trig.xc external call table.

The remainder of the external call table is a list of definitions which map C functions to GT.M routines; one per line. Ours will look like this:


sin: gtm_status_t m_sin(I:gtm_double_t*, O:gtm_double_t*)
cos: gtm_status_t m_cos(I:gtm_double_t*, O:gtm_double_t*)
tan: gtm_status_t m_tan(I:gtm_double_t*, O:gtm_double_t*)

Using the sin function, let’s break down the format of one of these lines:

  • sin: is the name by which this function will be referred when called by our MUMPS code
  • gtm_status_t is the data type which will be returned by our C wrapper
  • m_sin is the name of our C wrapper function
  • I:gtm_double_t* specifies that the first parameter of our C wrapper is a pointer to a double-precision floating point value. The I specifies that this parameter is used for input to our C wrapper. In this case, this is the number to which the sin function will be applied.
  • O:gtm_double_t* specifies that the second and final parameter of our C wrapper is a pointer to a double-precision floating point value. The O (output) specifier indicates that GT.M will be passing a variable by reference for this parameter, and that our C wrapper will be populating it with a return value.

Here’s the completed external call table, trig.xc:


$HOME/lib/trig.so
sin: gtm_status_t m_sin(I:gtm_double_t*, O:gtm_double_t*)
cos: gtm_status_t m_cos(I:gtm_double_t*, O:gtm_double_t*)
tan: gtm_status_t m_tan(I:gtm_double_t*, O:gtm_double_t*)

C Wrapper Functions

For our C wrapper functions, there are a couple of important conventions to note:

  • The first parameter to each wrapper function must be an int. Although this is not (and must not be) specified in the external call table (trig.xc), it must be included in each wrapper function. GT.M will automatically pass to this parameter a value indicating the total number of parameters passed to our wrapper function. It is essentially the GT.M external call mechanism’s own implicit version of argc.
  • We must tell the preprocessor to include gtmxc_types.h which is located in $gtm_dist

Let’s look at the complete trig.c:

#include <math.h>
#include "gtmxc_types.h"

gtm_status_t m_sin(int c, gtm_double_t *x, gtm_double_t *out)
{
    *out = sin(*x);
    return(0);
}

gtm_status_t m_cos(int c, gtm_double_t *x, gtm_double_t *out)
{
    *out = cos(*x);
    return(0);
}

gtm_status_t m_tan(int c, gtm_double_t *x, gtm_double_t *out)
{
    *out = tan(*x);
    return(0);
}

The points that bear further discussion are the function definitions, such as m_sin(int c, gtm_double_t *x, gtm_double_t *out), and the pointer assignments, such as *out = sin(*x);

The function definitions are unique in that they use the typedefs (defined in $gtm_dist/gtmxc_types.h) for the return type and parameter types. This should facilitate portability among the various flavors of UNIX and Linux that GT.M supports.

The assignments use pointers so that the output value (in this case, gtm_double_t *out) can be accessed from within the GT.M environment. The assignment *out = sin(*x); means that we are assigning the value of the sin function of the data pointed to by x into the memory location pointed to by out. This is what allows GT.M to retrieve the value from within its native environment. When dealing with C pointers, I find it useful to read the “flow” of the operation from right-to-left.

MUMPS Routine

Next, we will build a MUMPS routine to hide our use of the GT.M external call mechanism. This is a good idea in case you ever need to port your MUMPS application to a platform that uses different mechanisms for external calls, such as InterSystems Cache’.

Here is our MUMPS routine, trig.m:

trig ;; trigonometry wrappers

sin(num)
 new result
 do &trig.sin(num,.result)
 quit result

cos(num)
 new result
 do &trig.cos(num,.result)
 quit result

tan(num)
 new result
 do &trig.tan(num,.result)
 quit result

Although you could call the external routines directly, the wrapper-within-a-wrapper approach provides more readable code, hides the call-by-reference from the programmer using your routines, and gives you MUMPS code that is more idiomatically representative of the 1995 MUMPS ANSI standard.

The uniqueness of this routine is in the &wrapper.function() syntax. The &trig.function() syntax instructs GT.M to check the $GTMXC_trig environment variable to find the external call table it should use to execute function(). In official GT.M parlance, trig is a package. There is also a $GTMXC environment variable, which points to the callout table for what is referred to as the “default” package, but in the interests of portability and modularity, we will not cover its use here.

Compiling and Linking

Now that we have our MUMPS code (trig.m), our callout table (trig.xc), and our C wrappers (trig.c), we can create a Makefile to compile and link our wrapper functions into a shared library. Please note that this makefile is specific to Linux and may or may not work on other UNIX or UNIX-like operating systems.

CFLAGS=-Wall

all: trig.so

trig.so: trig.o
        gcc $(CFLAGS) -o trig.so -shared trig.o -lm

trig.o: trig.c
        gcc $(CFLAGS) -c -fPIC -I$(gtm_dist) trig.c

clean: 
        rm trig.so
        rm trig.o

install:
        cp trig.so $(HOME)/lib

Let’s break this down line by line:

  • CFLAGS=-Wall

This line gives us a variable for flags that we will always pass to the C compiler. -Wall instructs the compiler to enable all warning messages. This should always be used, as it will help you to write cleaner code.

  • all: trig.so

This is the first rule of the Makefile, which will be invoked automatically if make is run with no command-line arguments. It simply says that the rule “all” depends on “trig.so” to be considered complete. So, if “trig.so” does not exist, make will then scan the Makefile to find a rule to use to build “trig.so”

  • trig.so: trig.o

This is the rule for building “trig.so”. It simply means that trig.so depends on the existence of “trig.o” in order to build it. If “trig.o” does not exist, make will search for a rule to build “trig.o”

  • gcc $(CFLAGS) -o trig.so -shared trig.o -lm

This is the command necessary to generate “trig.so” from “trig.o”. The “-o” flag tells the linker to name the output “trig.so”. The “-shared” flag tells the linker that we wish to generate a shared library from “trig.o”. “-lm” tells the linker that this production depends on libm.so (the “-l” flag automatically prepends “lib” onto the library we specify. “-llibm” does not work).

  • trig.o: trig.c

This is the rule from building “trig.o” from “trig.c”. It informs make that trig.o requires trig.c in order to be built. Since there is no rule in this Makefile for generating “trig.c”, make will look for “trig.c” in the current working directory.

  • gcc $(CFLAGS) -c -fPIC -I$(gtm_dist) trig.c

This is the command necessary to generate “trig.o” from “trig.c”. The “-c” flag instructs gcc to compile, but not link, the specified file. The “-fPIC” flag instructs gcc to generate position-independent code, which means that the symbols in the object file may be relocated and resolved at load time rather than link time, which is necessary for shared libraries. The “-I$(gtm_dist)” flag tells the compiler that it should search $(gtm_dist) for header (.h) files. This is necessary because gtmxc_types.h will not likely be in a place that the compiler knows about. $(gtm_dist) is an environment variable which is required in order for GT.M to function, and will always contain the path in which gtmxc_types.h is located.

Putting it all together

When you have trig.m, trig.c, trig.xc, and Makefile typed in, run the following commands from the shell prompt:

$ cp trig.m $HOME/p/
$ make
$ make install
$ export GTMXC_trig=$HOME/lib/trig.xc
$ mumps -dir
GTM> w $$sin^trig(2.53)

GT.M will respond by writing .574172 to the screen.

Where to go next

Refer to the GT.M UNIX Programmer’s Manual for more information on advanced uses of the GT.M external call mechanism.

I hope this article proves useful, and welcome your feedback!