# Errors: panic, Fallible, ?

There is no null and no exception. An absent value is `Option`, a failure is `Result`, and `?` sends a failure to the caller unchanged.

## Option, Result, and ?

`Option<T>` is `Some` or `None`. `Result<T, E>` is `Ok` or `Err`. Both are ordinary enums, so `match` covers them and the compiler counts the arms.

`?` after an expression unwraps the success and returns the failure to the caller. It changes no types on the way out: the whole value is copied into a function that returns the same type, so there is no residual type to convert.

```vyrn
// There is no null. An absent value is `Option<T>`, a failure is
// `Result<T, E>`, and `?` returns the failure to the caller untouched.
import { joinWith } from "std/strings"
import { parseInt64 } from "std/num"

fn doubled(text: String) -> Result<Int64, String> {
    return match parseInt64(text) {
        Some(v) => Ok(v * 2),
        None => Err("not a number: " + text),
    }
}

// `?` unwraps the success and returns the error to this function's caller.
fn quadrupled(text: String) -> Result<Int64, String> {
    let twice = doubled(text)?
    return Ok(twice * 2)
}

fn showResult(r: Result<Int64, String>) -> String {
    return match r {
        Ok(n) => n.toString(),
        Err(why) => why.copy(),
    }
}

export fn demo() -> String {
    return joinWith([showResult(quadrupled("7")), showResult(quadrupled("seven"))], "\n")
}

fn main() -> Int64 {
    print(demo())
    return 0
}
```

Built output:

```
28
not a number: seven
```

## Fallible

`?` also works on a type you declare. Implement [Fallible](https://vyrn-lang.github.io/docs/std/fallible.html): say whether a value is a success, and how to read the success payload. The operator resolves through the protocol.

The failing value reaches the caller with its payload intact, because nothing looked inside it.

`panic(msg)` ends the program with a message. It is for a case that cannot happen — an arm the operator never calls — and not for a failure a caller could handle. There is no unwinding anywhere in the language, so a panic does not become a catch somewhere up the stack.

```vyrn
// `?` works on your own type too: implement `Fallible`, say which side of the
// sum a value is on and how to read the success, and the operator resolves
// through it. The failure reaches the caller with its payload intact.
import { Fallible } from "std/fallible"
import { joinWith } from "std/strings"

type Http = enum {
    Body(String),
    NotFound,
    ServerError(String) }

impl Fallible for Http {
    type Output = String

    fn isSuccess(self) -> Bool {
        return match self {
            Body(b) => true,
            NotFound => false,
            ServerError(m) => false,
        }
    }

    fn success(self) -> Output {
        return match self {
            Body(b) => b.copy(),
            // `?` calls this only after `isSuccess` answered true, so these arms
            // are unreachable. `panic` is how an arm says it has no value.
            NotFound => panic("success on NotFound"),
            ServerError(m) => panic("success on ServerError"),
        }
    }
}

fn fetch(code: Int64) -> Http {
    if code == 200 {
        return Body("hello")
    }
    if code == 404 {
        return NotFound
    }
    return ServerError("upstream timed out")
}

fn shout(code: Int64) -> Http {
    let body = fetch(code)?
    return Body(body + "!")
}

fn describeHttp(h: Http) -> String {
    return match h {
        Body(b) => "body " + b,
        NotFound => "not found",
        ServerError(m) => "server error: " + m,
    }
}

export fn demo() -> String {
    return joinWith([describeHttp(shout(200)), describeHttp(shout(404)), describeHttp(shout(500))], "\n")
}

fn main() -> Int64 {
    print(demo())
    return 0
}
```

Built output:

```
body hello!
not found
server error: upstream timed out
```

---

From https://vyrn-lang.github.io/guide/errors.html — generated by `site/export.vyrn` from the Vyrn repository.
