Skip to main content

Gotchas & Tips

Common pitfalls when writing MOISSCode protocols, and how to avoid them.


Reserved Keywords

The following words are reserved by the parser and cannot be used as variable or function names:

KeywordUsed For
severityAlert severity declaration
protocolProtocol definition
inputInput declaration
letVariable binding
if, elseConditionals
while, for, inLoops
track, usingKAE tracking
assessClinical assessment
alertClinical alerts
administer, doseDrug administration
importModule imports
type, extendsType definitions
function, returnFunction definitions
true, false, nullLiterals
and, or, notLogical operators
Common Mistake
// ❌ WRONG - "severity" is a keyword!
let severity = med.scores.qsofa(p);

// ✅ CORRECT - use a different name
let qsofa_score = med.scores.qsofa(p);

No Dictionary Literals

MOISSCode does not support inline dictionary/map {} syntax. Curly braces are reserved for type constructors and code blocks.

// ❌ WRONG - dict literal not supported
let result = med.lab.interpret_panel("CBC", {"WBC": 18.5, "Hgb": 8.2});

// ✅ CORRECT - use individual calls instead
let wbc = med.lab.interpret("WBC", 18.5);
let hgb = med.lab.interpret("Hgb", 8.2);

Constructor syntax IS supported:

type Isolate {
organism: str;
mic: float;
}

let iso = Isolate { organism: "E.coli", mic: 0.5 };

All Numbers Are Floats

The parser converts all numeric literals to floats, even integers like 90. If you pass a number to a library function that expects an integer (e.g., for list slicing or array indexing), the module must handle the conversion internally.

For protocol authors, this is transparent - just write numbers normally:

let sir = med.epi.sir_model(100000, 10, 0.3, 0.1, 90);

For module developers building new med.* engines in Python, always cast parameters that must be integers:

def sir_model(self, population, initial_infected, beta, gamma, days=100):
days = int(days) # Parser sends 90.0, not 90
population = int(population)
# ...

File Encoding (BOM)

When reading .moiss files programmatically (outside the CLI), use utf-8-sig encoding to handle the optional BOM (Byte Order Mark) that some editors add:

# ❌ May fail if file has BOM
with open("protocol.moiss", encoding="utf-8") as f:
code = f.read()

# ✅ Handles BOM transparently
with open("protocol.moiss", encoding="utf-8-sig") as f:
code = f.read()

The CLI's moiss run command handles this automatically.


Supported Expression Types

Function arguments in MOISSCode can only be:

TypeExampleNotes
Numbers42, 3.14Always parsed as float
Strings"hello"Double-quoted
Booleanstrue, falseLowercase
nullnullNull value
Lists["a", "b", "c"]Square brackets
Variablesp, scoreIdentifiers
Dot accessp.hr, med.scores.qsofa(p)Member access
ConstructorsType { field: val }Custom types only

Not supported as expressions: inline dicts {}, lambdas, ternaries.


Naming Functions and Variables

  • Protocol names: PascalCase - SepsisScreen, ICU_Admission
  • Variable names: snake_case - qsofa_score, gfr_result
  • Function names: snake_case - renal_stage, classify_bmi
  • Type names: PascalCase - CultureResult, OutbreakReport

Import Statements

Imports are declarative only - they don't affect which modules are available. All med.* modules are always loaded. However, including them is good practice for readability:

import med.lab;
import med.nutrition;
import med.pk;