Mumps is a general purpose language with a built-in hierarchical data base facility, a large user community (mainly biomedical), and a diversified installed software applications base. Mumps lacks, however, many tools and facilities common to modern programming environments. This paper describes an experimental set of C++ class libraries that make accessible to a C++ programmer the key elements and features of the Mumps language while at the same time extending the range of tools available to the medical applications developer.
The Mumps language, as it was originally called, originated in the mid-60's at the Massachusetts General Hospital [Barnett 1970, Bowie and Barnett 1976]. It became widely used in biomedical settings and gained a following in several commercial environments as well. A large number of interpreters and compilers exist [Mumps Technology Association 1994] and it is available on many computer systems. There are ANSI and DOD approved standards [National Bureau of Standards 1976, ANSI 1990] for Mumps. The name for the language was changed in recent years by vote of the Mumps Users' Group.
Since its initial development, Mumps evolved into a high level programming environment and underwent substantial evolution. As originally conceived, Mumps differed from other small computer based languages in the following ways:
1. It provided for an easily manipulated hierarchical data base that was ideally
suited to medical records storage and retrieval.
2. It provided flexible string handling support.
3. Its compact representation allowed multiple concurrent tasks in limited
memory environments on very small machines.
Syntactically, Mumps was built on an earlier language named JOSS and has an appearance that is similar to early versions of Basic that were likewise based on JOSS. Although most current versions of Mumps are compiled, Mumps retains a fundamentally interpretive foundation that still allows direct execution of dynamically created code.
Initially, the structure of the language was limited by the constraints imposed by the primitive minicomputers on which it was originally implemented. An early design goal for Mumps was to provide multi-user, time shared access although the early minicomputers on which it was originally implemented had very limited memory and mainly single user operating systems. Consequently, early implementations of Mumps were standalone, interpreter based, single language operating systems. In these implementations, each user was assigned a very small region of memory for both code and local data. Code was loaded from external storage and stored in memory in source form. Typical program partitions were less than 4,000 bytes, including all data, stacks, code and buffers. This allowed multiple time-shared partitions on even the smallest machines. Because of these limitations, there was a high premium for compact, abbreviated, concise program representation. Mumps language processors were originally developed as interpreters in order to conserve disk and memory space. Since Mumps programs were mainly interactive or data base access dependent, direct interpretation of source code did not constitute a serious penalty to performance.
The early use of source code representation of programs both on external storage and in memory was justified in terms of savings in size of program modules. Since Mumps was a very high level language, a source code module took very much less space on early expensive, limited, external direct access devices and consumed far less memory when loaded than corresponding binary executable modules. Additionally, shorter source modules took less time to transfer from external to internal storage that was important in systems that tended to have a very large number of relatively short routines.
The premium on program (i.e., source code) size limited if not completely discouraged program documentation (commenting) and also led to a variety of programming practices that can be described at best as expedient. Many of these practices are still retained in the current language standard and are orthogonal to good programming practices. For example, consider the following:
Indirect execution of other lines of code, including comments. Through builtin functions the text contents of lines in the resident source module could be extracted and executed. Source code lines are located either by labels or offsets from labels. This led to the ludicrous practice of deliberate and intentional execution of comments. Although most modern Mumps systems now compile the source code, the legacy of the past still permits direct execution of source code text.
Branching within a module and branching to other, separate modules, using a numeric offset relative to a label or entry point. This practice was also used, as noted above, to locate lines of text for possible execution. Thus, for example, an Mumps programmer can branch to the fifth line relative to a label in a different program. Any change in a target program requires backwards modification of all programs that reference it but with no adequate means to locate the referencing programs. Since Mumps based systems tend to consist of many hundreds of independent modules, even the insertion of a comment into a module can have unpredictable consequences at some later, unspecified time. Given the often critical medical applications that are programmed in Mumps, this is a very serious problem.
Mumps allows the dynamic construction and execution of strings and expressions. This allows Mumps programs to write and execute additional code. Sometimes code fragments are embedded in the data base, in others the user of the program enters data that determines or becomes executable code. This feature places an intolerable burden on management from the standpoints of security, software testing, and maintenance. No one can ever be certain what an Mumps program will ultimately execute if parts of the code are derived from user and data base sources after compilation.
Functional modules then, as now, were highly task specific, many in number, and loaded frequently from a library. A typical application consisted of a tree-like hierarchy of modules that often corresponded to the structure of the data base in an early form of object-oriented programming. An excellent example of a system structured this way can be found in the structure of the COSTAR System [Barnett 1979] that employed well over a thousand separate code modules to service an ambulatory patient record data base. In effect, modules and data were tightly coupled and encapsulated.
References
American National Standards Institute, Inc. X11.1 M Programming Language 1990
Barnett, G. Octo; and Greenes, R. A. (1970). High level programming languages, Computers and Biomedical Research, Vol 3, pp 488-497.
Barnett, G.O.; et al., COSTAR - a computer-based medical information system for ambulatory care, Proc of the IEEE, Vol 67, No 9 (1979).
Bowie, J.; and Barnett G.O., MUMPS - an economical and efficient time-sharing language for information management, Computer Programs in Biomedicine, Vol 6, p 11 (1976).
M Technology Association, M Sources ' 94, M Technology Association, 1738 Elton Road, Suite 205, Silver Spring, Maryland 20903, Tel: (301) 431-4070., Fax: (301) 431-0017 (1994)
National Bureau of Standards, MUMPS Language Standard, NBS Handbook 118, National Bureau of Standards SD Cat. No. C13.11.118, U.S. Government Printing Office, Washinton (1976).
O'Kane, K.C., A portable hybrid MUMPS development host, Proc IEEE Comp Soc 7th International Computer Software & Applications Conference, p 60 (1983).
O'Kane, K.C.; An expert systems and relational data base management facility for Mumps, Computers in Biology and Medicine, Vol 16, No. 3 (1986).
O'Kane, K.C.; A language for implementing information retrieval software, Online Review, Vol 16, No 3, pp 127-137 (1992).
O'Kane, K.C., and McColligan, E. E., An Object Oriented Medical Record, (1994, in progress).
Read !,"Enter patient SSN: ",ssn
If '$Data(^pat(ssn))!ssn'?3N"-"2N"-"4N Write !,"Patient Does Not
Exist",!! Quit
Read !,"Enter test name: ",test
Read !,"Enter result: ",rslt
Read !,"Enter date: ",date
Set ^pat(ssn,date,test)=rslt
Set date="-1"
L1 Set date=$Next(^pat(ssn,date))
If date<0 Quit
Set test="-1"
L2 Set test=$Next(^pat(ssn,date,test))
If test<0 Goto L1
Write !,"Name ",^pat(ssn),"; Date: ",date,"; Test: ",test
Write !,"; Result: ",^pat(ssn,date,rslt),!
Goto L2
Figure 1
Kevin C. O'Kane