Functions in MUMPS
Learn how MUMPS organizes reusable code with subroutines and extrinsic functions, including parameters, return values, recursion, scope, and pass-by-reference using Docker-ready YottaDB examples
MUMPS is an imperative, procedural language, and it splits reusable code into two distinct forms. A subroutine is a labelled block of code you invoke with the DO command; it runs for its side effects and returns nothing. An extrinsic function is a labelled block you invoke with the $$ prefix; it computes and returns a value via QUIT. Understanding when to reach for each is the heart of structuring MUMPS programs.
Because MUMPS routines are just files full of labels, “defining a function” means writing a label and indented code beneath it. There is no function or def keyword. A label that ends with QUIT (no argument) is effectively a subroutine; a label that ends with QUIT value is an extrinsic function. The same label can even be entered both ways, though that is rare in practice.
Two features make MUMPS functions distinctive. First, the language is typeless — parameters and return values are the same universal value, coerced between string, integer, and floating-point as needed. Second, MUMPS variables are global to the whole process by default, so the NEW command exists specifically to give a subroutine its own private copies. This page covers parameters, return values, recursion, scope with NEW, and the difference between pass-by-value and pass-by-reference.
Subroutines and Extrinsic Functions
The example below puts the core ideas together in one routine. Remember the MUMPS layout rules: labels start in column 1, and executable code must be indented with a leading space.
Create a file named functions.m:
functions ; Functions in MUMPS - subroutines and extrinsic functions
do greet
do welcome("Grace")
write "Square of 7 is ",$$square(7),!
write "3 + 4 = ",$$add(3,4),!
write "5! = ",$$fact(5),!
do scopedemo
quit
;
greet ; Subroutine: no parameters, no return value
write "Hello from a subroutine!",!
quit
;
welcome(name) ; Subroutine with one parameter
write "Welcome, ",name,"!",!
quit
;
square(n) ; Extrinsic function: returns a value with QUIT
quit n*n
;
add(a,b) ; Extrinsic function with two parameters
new sum
set sum=a+b
quit sum
;
fact(n) ; Recursive extrinsic function: factorial
if n<2 quit 1
quit n*$$fact(n-1)
;
scopedemo ; Demonstrate local scope with NEW
new i,total
set total=0
for i=1:1:5 set total=total+i
write "Sum of 1 to 5 = ",total,!
quit
How It Works
do greet— TheDOcommand calls a subroutine by label.greettakes no arguments and prints a line. Control returns to the caller whengreethits itsQUIT.do welcome("Grace")— Subroutines can take parameters. The formal parameter list(name)appears right after the label, and the argument"Grace"is bound tonamefor the duration of the call.$$square(7)— The$$prefix invokes an extrinsic function. UnlikeDO, this form produces a value, so it can be used anywhere a value is expected — here, directly inside awrite. The function returns withquit n*n, where the argument ofQUITis the return value.$$add(3,4)— Functions accept multiple comma-separated parameters. Inside,new summakessuma private variable so the function never disturbs a caller’s variable of the same name.$$fact(5)— Recursion is natural in MUMPS. The postconditional-freeif n<2 quit 1returns the base case; otherwise the line falls through toquit n*$$fact(n-1), which calls the function again with a smaller argument.do scopedemo— Loops over1:1:5(start:step:stop), accumulating intototal. Bothiandtotalare protected withNEWso they vanish when the subroutine returns.
Full Command Names vs Abbreviations
Every MUMPS command can be abbreviated to its first letter. The routine above uses full names for clarity, but production code is almost always terse. Here is the same factorial logic written in fully abbreviated form as a complete, runnable routine.
Create a file named abbrev.m:
abbrev ; abbreviated form - terse MUMPS style
w "5! = ",$$fact(5),!
q
fact(n) ; recursive factorial
i n<2 q 1
q n*$$fact(n-1)
Here w is WRITE, q is QUIT, and i is IF. Likewise s is SET, n is NEW, and d is DO. The abbreviated routine prints the same 5! = 120 line as before; both styles run identically.
Pass-by-Value vs Pass-by-Reference
By default, parameters are passed by value — the function gets a copy, and changes do not leak back to the caller. MUMPS can also pass by reference by prefixing the argument with a dot (.) at the call site. A referenced parameter is an alias for the caller’s variable, so changes are visible after the call. This is how MUMPS subroutines “return” extra results without being functions.
Create a file named byref.m:
byref ; Pass-by-value vs pass-by-reference in MUMPS
set num=10
do dblval(num)
write "After dblval, num = ",num,!
do dblref(.num)
write "After dblref, num = ",num,!
quit
;
dblval(x) ; Receives a copy - changes do not affect the caller
set x=x*2
quit
;
dblref(x) ; Receives a reference - the dot at the call site links it
set x=x*2
quit
The two subroutines have identical bodies; only the call site differs. do dblval(num) passes a copy, so num is untouched. do dblref(.num) passes a reference, so doubling x inside the subroutine doubles num in the caller.
Running with Docker
Run both routines with the YottaDB image. The -run flag executes the routine whose name matches the entry label and file name.
| |
-v $(pwd):/appmounts your current directory into the container at/app.-e ydb_routines=/apptells YottaDB where to find your.mroutine files.yottadb -run functionsruns the routine namedfunctions(fromfunctions.m).
Expected Output
Running functions:
Hello from a subroutine!
Welcome, Grace!
Square of 7 is 49
3 + 4 = 7
5! = 120
Sum of 1 to 5 = 15
Running byref:
After dblval, num = 10
After dblref, num = 20
Running abbrev:
5! = 120
Key Concepts
- Two forms of reuse — Use
DO labelfor subroutines (run for side effects, no return value) and$$label(args)for extrinsic functions (compute and return a value viaQUIT value). - No function keyword — A “function” is just a label with a formal parameter list
(a,b)and indented code;QUITends it and optionally carries a return value. - Typeless parameters — Arguments are the one universal MUMPS value, coerced between string and number on demand, so the same function works on
"7"or7. - Scope is process-wide by default — Variables persist across subroutine calls unless you protect them with
NEW, which restores their prior state onQUIT. - Pass-by-reference with a dot — Prefixing an argument with
.(e.g.do sub(.x)) lets a subroutine modify the caller’s variable, a common way to return multiple results. - Recursion is natural — Extrinsic functions can call themselves with
$$, as the recursive factorial shows; a postconditional orIFguards the base case. - Abbreviate freely — Every command shrinks to its first letter (
d,w,s,n,q,i), and idiomatic MUMPS code uses these heavily.
Running Today
All examples can be run using Docker:
docker pull yottadb/yottadb-base:latest-master
Comments
Loading comments...
Leave a Comment