Structuring Python for Mission-Critical Aerospace Standards
When developing software for safety-critical environments like the Joint Strike Fighter (JSF) Air Vehicle, predictability, determinism, and rigorous mathematical analyzability are paramount. The JSF AV coding standards were engineered to guarantee that software behaves exactly as intended under extreme conditions, with no hidden surprises.
https://www.stroustrup.com/JSF-AV-rules.pdf
Python, by its nature, is a highly dynamic, flexible, and forgiving language. If one were to adapt Python to meet the strict requirements of this aerospace standard, many of the language’s most beloved features and built-in functions would have to be strictly forbidden. Here is a breakdown of the core Python functions and paradigms that are not allowed under the standard, and the engineering rationale behind their prohibition.
1. Exception Handling (try, except, finally, raise)
In standard Python development, wrapping code in try and except blocks is the idiomatic way to handle errors. Under the JSF AV standard, this entire paradigm is completely banned.
Why it is not allowed: Exceptions introduce hidden, non-deterministic jump points in the execution of the program. When an error is raised, the program breaks its linear, predictable control flow and searches the call stack for an appropriate handler. In mission-critical software, every possible path of execution must be mathematically verifiable and tested.
Exceptions obscure the control flow graph, making it nearly impossible to guarantee execution time, state consistency, or memory stability when an error occurs. Instead, functions must return explicit error codes or status flags that are manually checked by the caller.
2. Recursion (Functions calling themselves)
A common algorithmic approach in Python is to use recursion—where a function calls itself to solve smaller instances of a problem (e.g., traversing a tree or calculating a factorial).
Why it is not allowed:
The standard strictly forbids any function from calling itself, either directly or indirectly. Recursion relies on dynamically allocating new frames on the call stack for every recursive jump. In an embedded aerospace system, memory is severely constrained and must be strictly bounded.
If a base case fails or an input is unexpectedly large, recursion can cause unbounded stack growth, ultimately resulting in a stack overflow and a catastrophic system crash. All repetitive logic must be rewritten using deterministic for or while loops.
3. Dynamic Execution and Metaprogramming (eval(), exec(), setattr())
Python allows developers to evaluate strings as code at runtime using eval(), execute dynamic blocks using exec(), or alter the structure of objects on the fly using setattr() (often called monkey-patching).
Why it is not allowed:
The standard mandates that there shall be absolutely no self-modifying code. The software that is analyzed, tested, and compiled on the ground must be the exact same software executing in the air. Dynamic execution allows the program’s logic and structure to change during runtime, which completely invalidates static analysis, security audits, and structural coverage reports.
4. System Interruption and Environment Hooks (sys.exit(), os.system(), os.environ)
Python developers frequently use sys.exit() to terminate a script early, or os.system() and subprocess modules to interact with the underlying operating system.
Why it is not allowed:
Mission-critical systems operate continuously and cannot abruptly “exit” or terminate their host processes without severe consequences. Functions like sys.exit() bypass the normal, controlled shutdown sequences of the hardware. Furthermore, interacting with the host environment via system calls or environment variables introduces dependencies on external, unverified factors. The software must be entirely self-contained and isolated from unpredictable operating system states.
5. Unbounded Arguments (*args, **kwargs)
Python functions can accept a variable number of positional or keyword arguments using *args and **kwargs.
Why it is not allowed:
The standard requires interfaces to be strictly defined, visible, and bounded. Banning variable argument lists ensures that the exact number and type of inputs to any function are known at design time. Additionally, the standard enforces a hard limit on the total number of arguments a function can accept (e.g., maximum of 7). Unbounded arguments prevent the compiler and static analysis tools from verifying that a function is being called safely and correctly.
6. Untyped Dynamic Data Structures (Raw list, dict, and mixed types)
Python lists and dictionaries can dynamically grow in size and can hold mixed data types simultaneously (e.g., my_list = [1, “two”, 3.0]).
Why it is not allowed:
There are two reasons these structures violate the standard:
Dynamic Memory Allocation: Native lists and dictionaries resize themselves automatically, which requires dynamic memory allocation under the hood. The standard severely restricts dynamic memory allocation because it can lead to memory fragmentation and out-of-memory errors during operation.
Type Ambiguity: The standard forbids mixed-type data structures (analogous to banning unions). Every variable and collection must have a single, statically defined, and unambiguous type to prevent runtime type-casting errors or data corruption. Bounded, strictly typed, and pre-allocated arrays must be used instead.









































