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