Why does EK9 reject a call nested inside a throw expression?

← Code Quality · Ref: Q1303

EK9 rejects a call nested inside a throw (E11070) when the thrown expression is itself a call applied to the result of another call (a higher-order chain such as throw getFactory("std")("oops")). The exception construction is hidden behind that chain. Extract each step into a local variable and throw the variable, so the exception is materialised and the throw site stays readable. The two valid forms are a direct constructor call (throw Exception(reason)) or a previously-declared variable (throw ex).

See Q311 for quality checks.

Example

defines module qa.quality.throw.nested.call

  defines function

    ExceptionFactory() as pure abstract
      -> reason as String
      <- builtException as Exception?

    StandardExceptionFactory() is ExceptionFactory as pure
      -> reason as String
      <- builtException as Exception: Exception(reason)

    getExceptionFactory()
      -> kind as String
      <- chosen as ExceptionFactory: StandardExceptionFactory
      if kind == "alt"
        chosen: StandardExceptionFactory

    //FIX: extract the factory selection and the exception into local
    //variables, then throw the variable. No call is nested in another
    //call at the throw site.
    raiseFailure()
      -> kind as String
      factory <- getExceptionFactory(kind)
      ex <- factory("operation failed")
      throw ex

  defines program

    NestedCallInThrowDemo()
      stdout <- Stdout()
      try
        raiseFailure("std")
      catch
        -> caught as Exception
        stdout.println(caught.reason())

Common mistakes

E11070 — Throwing a call applied to another call's result hides the exception construction at the throw site — extract the factory and exception into local variables and throw the variable. See ek9 -h E11070 for details.

Incorrect:

      throw getExceptionFactory(kind)("operation failed")

Correct:

      factory <- getExceptionFactory(kind)
      ex <- factory("operation failed")
      throw ex
Other ways to ask this
  • What triggers E11070 NESTED_CALL_IN_THROW?
  • Why can't I throw the result of a call chain directly?
  • How do I throw an exception produced by a factory call in EK9?

Coming from another language?

Java: throwing the result of a factory chain is unchecked by the compiler. Python/Go: no detection. EK9: compile-time error (E11070) requiring the thrown exception to be a direct constructor call or a previously-declared variable, never a call applied to a call.

Keywords: throw, call, extract, E11070, exception, quality, nested