An escape hatch is an “adapter” language feature, used to embed a fragment written in a lower-level language inside a larger fragment written in a higher-level language.

An example from the world of general-purpose programming languages (GPLs): many C compilers let you embed inline assembly (a lower-level language) in your C code (a higher-level language). Here is an example of inline assembly in GCC (GNU C Compiler) syntax for an Intel architecture processor:

    /* Add 10 and 20 and store result into register %eax */
    __asm__ ( "movl $10, %eax;"
                "movl $20, %ebx;"
                "addl %ebx, %eax;"
    );

And it goes further: if your assembler does not know how to translate a particular CPU instruction, you can use a special db instruction to emit bytes directly into the output. This is an escape hatch from assembly into machine code.

In the context of MPS-based DSLs there are multiple examples of escape hatches.

  • Many MPS languages use query functions (also called concept functions) to let you write logic in Java where predefined constant values are not enough.

  • The MPS build language, whose job it is to generate Ant files from a higher level description of your project modules and their dependencies, lets you embed bits of Ant XML into your build files.

Escape hatches give power to language users. Without an escape hatch they might have to postpone their work and pressure you, the DSL developer, to publish a new release of your DSL. A well-designed escape hatch may help them work around a missing feature in the DSL and get on with their work, releasing the pressure on you. And by seeing their workarounds you might also get a better idea of the semantics of the missing feature.

This extra power is not without its downsides. Inline assembly in a C program is architecture-specific: an Intel assembly will not work on an ARM CPU. Java-based query functions will not work in a JavaScript environment and Ant XML fragments cannot be directly used in Gradle build files.

Therefore, avoid building escape hatches that lead directly to your implementation language. But do build escape hatches to lower-level technology-independent languages.