Intermediate

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 — The DO command calls a subroutine by label. greet takes no arguments and prints a line. Control returns to the caller when greet hits its QUIT.
  • do welcome("Grace") — Subroutines can take parameters. The formal parameter list (name) appears right after the label, and the argument "Grace" is bound to name for the duration of the call.
  • $$square(7) — The $$ prefix invokes an extrinsic function. Unlike DO, this form produces a value, so it can be used anywhere a value is expected — here, directly inside a write. The function returns with quit n*n, where the argument of QUIT is the return value.
  • $$add(3,4) — Functions accept multiple comma-separated parameters. Inside, new sum makes sum a private variable so the function never disturbs a caller’s variable of the same name.
  • $$fact(5) — Recursion is natural in MUMPS. The postconditional-free if n<2 quit 1 returns the base case; otherwise the line falls through to quit n*$$fact(n-1), which calls the function again with a smaller argument.
  • do scopedemo — Loops over 1:1:5 (start:step:stop), accumulating into total. Both i and total are protected with NEW so 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.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Pull the YottaDB image
docker pull yottadb/yottadb-base:latest-master

# Run the functions routine
docker run --rm -v $(pwd):/app -e ydb_routines=/app yottadb/yottadb-base:latest-master yottadb -run functions

# Run the pass-by-reference routine
docker run --rm -v $(pwd):/app -e ydb_routines=/app yottadb/yottadb-base:latest-master yottadb -run byref

# Run the abbreviated factorial routine
docker run --rm -v $(pwd):/app -e ydb_routines=/app yottadb/yottadb-base:latest-master yottadb -run abbrev
  • -v $(pwd):/app mounts your current directory into the container at /app.
  • -e ydb_routines=/app tells YottaDB where to find your .m routine files.
  • yottadb -run functions runs the routine named functions (from functions.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 label for subroutines (run for side effects, no return value) and $$label(args) for extrinsic functions (compute and return a value via QUIT value).
  • No function keyword — A “function” is just a label with a formal parameter list (a,b) and indented code; QUIT ends 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" or 7.
  • Scope is process-wide by default — Variables persist across subroutine calls unless you protect them with NEW, which restores their prior state on QUIT.
  • 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 or IF guards 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
Last updated:

Comments

Loading comments...

Leave a Comment

2000 characters remaining