How do sanitized parameters interact with pure functions in EK9?
← Security and Sanitization · Ref: Q217
Purity does not change how a sanitized parameter is used. The receiving function cleans the parameter on entry, pure or not, and the same rule applies in both: a sanitized parameter cannot be aliased into a new local (E07930). What purity adds is a ban on mutation operators such as :=: and :~: (E08120).
PURE FUNCTION
Use the parameter directly, or copy it:
pureProcess() as pure -> input as sanitized String <- result as String? localCopy <- String(input) result: localCopy
The copy constructor creates an independent value. 'localCopy <- input' would be E07930, exactly as it is in a function that is not pure. Assigning the parameter to the return variable, or using it in an expression, is allowed.
WHY THEY INTERACT
Purity prevents mutation and side effects. The no-alias rule prevents two names sharing the receiver's cleaned copy. Neither depends on the other.
NON-PURE FUNCTION
A function that is not pure may also copy into an existing variable:
safeCopy <- String(input) result: "" result :=: safeCopy // copy operator result :~: safeCopy // merge operator
EXPRESSION USE
Both pure and non-pure can use sanitized parameters directly in expressions:
result: "Prefix: " + input
Concatenation creates a new value, so no aliasing risk.
See Q215 for sanitized basics. See Q54 for pure functions. See Q141 for constant immutability. See Q273 for purity as security boundary. See Q662 for safe copy patterns. See Q666 for injection pure context.
Example
defines module qa.security.pure defines function // Pure function: copy the parameter rather than alias it (E07930 applies in every function) pureWithSanitized() as pure -> input as sanitized String <- result as String? // An independent copy; 'cleanInput <- input' would be E07930 cleanInput <- String(input) result: "Clean: " + cleanInput // Non-pure may also copy into an existing variable nonPureWithSanitized() -> input as sanitized String <- result as String? // Option 1: Copy constructor (works in every function) safeCopy <- String(input) // Option 2: :=: on an initialized variable (not allowed in a pure function) result: "" result :=: safeCopy // Direct expression use works in both contexts directUse() as pure -> input as sanitized String <- result as String? // Concatenation creates new value — safe result: "Output: " + input defines program SanitizedPureDemo() stdout <- Stdout() userInput <- "external input" // === PURE + SANITIZED === result1 <- pureWithSanitized(userInput) if result1? stdout.println(result1) // === NON-PURE + SANITIZED === result2 <- nonPureWithSanitized(userInput) if result2? stdout.println(result2) // === DIRECT EXPRESSION === result3 <- directUse(userInput) if result3? stdout.println(result3) stdout.println("A sanitized parameter is never aliased into a local")
Common mistakes
E07930 — Assigning a sanitized parameter straight into a new local makes the local an alias of the parameter. That is E07930 in every function, pure or not. Use the copy constructor String(input) for an independent copy. See ek9 -h E07930 for details.
Incorrect:
cleanInput <- input
Correct:
cleanInput <- String(input)
Other ways to ask this
- Does a pure function need a copy constructor for a sanitized parameter?
- How do purity and sanitization work together in EK9?
- What is the copy constructor pattern for sanitized parameters?
Coming from another language?
Java: no purity concept, PreparedStatement for SQL safety. Python: no purity enforcement. Rust: ownership model prevents some aliasing. Go: no purity. Kotlin: no purity. Haskell: purity prevents side effects but no sanitization concept. EK9: the no-local-alias rule (E07930) for a sanitized parameter holds in every function; purity separately bans the mutation operators.
Keywords: side-effect, protect, sanitize, constructor, context, pure, copy, sanitized, safe, security, purity, immutable, function, defensive