In Python I use try/except for error handling. How does EK9's try/catch compare?

← Error Handling and Exceptions · Ref: Q1014

EK9 uses try/catch/finally, similar to Python's try/except/finally but with different syntax.

Python:

  try:
      result = risky_operation()
  except ValueError as e:
      print(f'Error: {e}')
  finally:
      cleanup()

EK9:

  try
    result <- riskyOperation()
  catch
    -> ex as Exception
    stdout.println(`Error: ${$ex}`)
  finally
    cleanup()

KEY DIFFERENCES:

- catch uses -> for the exception parameter (data flowing IN to the handler)
- EK9 has a base Exception that you extend into your own hierarchy (NetworkError extends Exception); it ships no large zoo of built-in ValueError/TypeError-style types
- A try has a single catch, not several except clauses; the catch may name a specific Exception subtype, or route several subtypes with a dispatcher
- The exception variable uses -> on its own line, like function parameters

TRY AS EXPRESSION:

Python has no try-expression. EK9 does:

  safeResult <- try
    <- rtn as String: "default"
    rtn: riskyOperation()
  catch
    -> ex as Exception
    rtn: "recovered"

Example

defines module qa.errorhandling.frompythonexception

  defines function

    riskyDivision() as pure
      ->
        numerator as Float
        denominator as Float
      <- rtn as Float: Float()

      if denominator?
        rtn: numerator / denominator

  defines program

    ExceptionDemo()
      stdout <- Stdout()
      stderr <- Stderr()

      // Like Python: try/except/finally
      try
        answer <- riskyDivision(10.0, 3.0)
        if answer?
          stdout.println(`Result: ${answer}`)
      catch
        -> ex as Exception
        stderr.println(`Caught: ${ex}`)
      finally
        stdout.println("Done")

      // Guard approach (simpler for functions that return unset)
      // The second denominator gives an unset result, so the guard fails and the else runs
      for denominator in [3.0, 0.0]
        if safeAnswer <- riskyDivision(10.0, denominator)
          stdout.println(`Got: ${safeAnswer}`)
        else
          stdout.println("Operation returned unset")

Common mistakes

E50060 — An Exception has no message() method; the text is read with ex.reason(), or the exception is converted with the $ operator or plain interpolation. Python's 'except Exception as ex' becomes 'catch' with '-> ex as Exception' on its own line. See ek9 -h E50060 for details.

Incorrect:

stderr.println(`Caught: ${ex.message()}`)

Correct:

stderr.println(`Caught: ${ex}`)
Other ways to ask this
  • What is the EK9 equivalent of Python's try/except/finally?
  • How do I catch exceptions in EK9 coming from Python?
  • How does EK9 exception handling differ from Python?

Coming from another language?

Python developers: try/except becomes try/catch. The catch uses '-> ex as Exception' on its own line. EK9 has a base Exception you can extend into your own hierarchy; there is no large built-in zoo of exception types.

Keywords: python, catch, finally, except, exception, try, migration