---
layout: ../../../layouts/DocsLayout.astro
title: Try/Exceptions
---
import InteractiveCode from "../../../components/InteractiveCode.astro";
import Code from "../../../components/Code.astro"

# Try/exceptions

Unlike PHP, in THP all errors must be explicitly declared
and handled.

## Declare that a function returns an exception

To declare a possible error return value the `Result` enum
is used.

For example, a function that returned a `DivisionByZero`
may be written like this:

<Code thpcode={`
fun invert(Int number) -> Int!DivisionByZero
{
    if number == 0
    {
        return DivisionByZero()
    }

    return 1 / number
}
`} />

In the previous segment, `Int!DivisionByZero` denotates
that the function may return either an `Int` or an `DivisionByZero`.

We then can return the error or success value;


### Multiple error returns

TODO: fix?



If there are multiple error types that the function can return,
you can use the `|` operator:

<Code thpcode={`
type Exceptions = Exception1 | Exception2 | Exception3

fun sample() -> Int!Exceptions
{ /* ... */}
`} />



## Error handling

The caller must handle all possible errors, they don't automatically
bubble up the stack.

THP provides syntax for handling errors following certain patterns,
via try expressions:

### Naked try

Use a naked `try` when you want to rethrow an error, if there is any.

<InteractiveCode 
    code={`
    fun dangerous() -> Int!Exception
    {   // May throw randomly
        return if Math.random() < 0.5 { 50 }
        else { Exception("Unlucky") }
    }

    fun run() -> !Exception
    {   // If \`dangerous()\` throws, the function exits with the same error.
        // Otherwise, continues
        val result = try dangerous()
        print("The result is {result}")
    }

    val res1 = run() // First, without error
    val res2 = run() // Then, an example with error
    `}
    steps={`
    step { line 14 }
    step { line 7 }
    step {
        line 8
        set "= = =" "run() = = = ="
    }
    step {
        line 10
        set " dangerous()" "..."
    }
    step {line 1}
    step {
        line 2
        set " = = =" "dangerous() = = = ="
    }
    step {line 3}
    step {set " Math.random()" "0.2"}
    step {
        unset " Math.random()"
        set "  return" "Int 50"
    }
    step {line 5}
    step {
        line 10
        unset "  return"
        unset " = = ="
        set " dangerous()" "Int 50"
    }
`}
></InteractiveCode>


In the previous example:

- If `dangerous()` returns an `Exception`, this exception
    will be returned by `run()`;
- If `dangerous()` succeedes, its value is assigned
    to `result`, and the function continues executing.


### Try/return

Try/return will return a new value if an expression fails,
otherwise will assign the success value and continue.

Try/return will run a function and assign its value if `Ok` is found.
Otherwise, it will return a new value specified by the programmer.

<Code thpcode={`
fun run() -> Int
{
    val result = try dangerous() return 0

    // ...
}
`} />

In the previous example:

- If `dangerous()` fails, its error will be ignored, and `0` will
    be returned from `run()`.
- If `dangerous()` succeedes, its value will be assigned to `result`,
    and the function continues executing.


### Try/else

Try/else will assign a new value if an expression fails.

<InteractiveCode
    code={`
    fun run(Int!Exception possible_value)
    {
        val mid = try possible_value else 666

        print("The value is: {mid}")
    }

    run(777)                // With an actual value
    run(Exception("oh uh")) // With an exception
    `}
    steps={`
    step {line 8}
    step {line 1}
    step {
        set "= = =" "run() = = = ="
        set "possible_value" "Int 777"
        line 2
    }
    step {line 3}
    step {
        line 5
        set "Int mid" "Int 777"
    }
    step {
        line 6
        out "The value is: 777"
    }
    step{
        unset "= = ="
        unset "possible_value"
        unset "Int mid"
        line 8
    }
    step{line 9}
    step{line 1}
    step {
        set "= = =" "run() = = = ="
        set "possible_value" "Exception(\\"oh uh\\")"
        line 2
    }
    step{line 3}
    step {
        line 5
        set "Int mid" "666"
    }
    step {
        line 6
        out "The value is: 666"
    }
    step{
        unset "= = ="
        unset "possible_value"
        unset "Int mid"
        line 9
    }
    step{line 0}
    `}
>
</InteractiveCode>

- If `possible_value` is an error, the value `666` is used.
- If `possible_value` is not an error, its value will be used.

Either way, the function will continue executing.


### Try/catch

Try/catch allows the error to be manually used & handled.


<Code thpcode={`
fun run()
{
    val result = try dangerous()
    catch Exception e
    {
        // This is run if \`dangerous()\` throws.
        // \`e\` is the thrown error

        // Handle the error
        // ...

        // Return a new value to be assigned to \`result\`
        0
    }
}
`} />

A try/catch may have many `catch` clauses:

<Code thpcode={`
try dangerous()
catch Exception1 e
{...}
catch Exception2 e
{...}
catch Exception3 e
{...}
`} />


