Improve docs on try/exceptions
This commit is contained in:
parent
b8c70f9550
commit
a449ea1085
@ -22,6 +22,17 @@
|
||||
color: var(--c-text-2);
|
||||
}
|
||||
|
||||
.markdown h3 {
|
||||
font-size: 1.35rem;
|
||||
line-height: 1.75rem;
|
||||
margin-bottom: 1rem;
|
||||
margin-top: 1.75rem;
|
||||
font-family: Inter, sans-serif;
|
||||
opacity: 0.9;
|
||||
font-weight: 600;
|
||||
color: var(--c-text-2);
|
||||
}
|
||||
|
||||
.markdown ul {
|
||||
list-style-type: disc;
|
||||
list-style-position: inside;
|
||||
|
@ -1,49 +1,150 @@
|
||||
---
|
||||
layout: ../../../layouts/PagesLayout.astro
|
||||
title: Try expressions
|
||||
title: Try/Exceptions
|
||||
---
|
||||
|
||||
# Try expressions
|
||||
# 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:
|
||||
|
||||
```thp
|
||||
fun get_value() -> Result[Int, String] { ... }
|
||||
|
||||
|
||||
// treating errors as normal enums
|
||||
val result = match get_value()
|
||||
case Ok(result) { result }
|
||||
case Err(error) { return error }
|
||||
|
||||
|
||||
// get the value if Ok, otherwise re-throw
|
||||
val result = try get_value()
|
||||
|
||||
// get the value if Ok, return a new value otherwise
|
||||
val result = try get_value() return Err("new error")
|
||||
|
||||
// get the value if Ok, assign a new value otherwise
|
||||
Int result = try get_value() else 20
|
||||
|
||||
// get the value if Ok, otherwise run block with the error value
|
||||
val result = try get_value()
|
||||
with error
|
||||
fun invert(Int number) -> Result[Int, DivisonByZero]
|
||||
{
|
||||
// handle error
|
||||
if number == 0
|
||||
{
|
||||
return Err(DivisionByZero())
|
||||
}
|
||||
|
||||
return Ok(1 / number)
|
||||
}
|
||||
```
|
||||
|
||||
In the previous segment, `Result[Int, DivisionByZero]` denotates
|
||||
that the function may return either an `Int` or an `DivisionByZero`.
|
||||
|
||||
To return the error we use `Err(...)`, and to return the succes value
|
||||
we use `Ok(...)`.
|
||||
|
||||
The error may be of any datatype.
|
||||
|
||||
|
||||
fun throws_exception() -> Result[Int, MyException|MyOtherException] { ... }
|
||||
### Multiple error returns
|
||||
|
||||
val result = try throws_exception() catch
|
||||
case MyException(e)
|
||||
{
|
||||
// deal with MyException
|
||||
}
|
||||
case MyOtherException(e)
|
||||
{
|
||||
// deal with MyOtherException
|
||||
}
|
||||
If there are multiple error types that the function can return,
|
||||
you can use the `|` operator:
|
||||
|
||||
```thp
|
||||
fun sample() -> Result[Int, Exception1|Exception2|Exception3]
|
||||
{ /* ... */}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Handle an error
|
||||
|
||||
Since `Result` is an enum we can use pattern matching to
|
||||
get the ok value, or handle the error:
|
||||
|
||||
```thp
|
||||
val result = match inverse(5)
|
||||
case ::Ok(value) { value }
|
||||
case ::Err(error) { return error }
|
||||
```
|
||||
|
||||
However, THP provides syntactic sugar for many common
|
||||
patterns for error handling.
|
||||
|
||||
## Try expressions
|
||||
|
||||
There are several try expressions that simplify error handling:
|
||||
|
||||
### Naked try
|
||||
|
||||
Using a `try` followed by an expression will execute the
|
||||
expression, and if `Ok` is returned, it will return it's value.
|
||||
If `Err` is returned, the error will be re-thrown.
|
||||
|
||||
```thp
|
||||
fun sample(Int x) -> Result[Int, DivisionByZero]
|
||||
{
|
||||
val result = try inverse(x)
|
||||
|
||||
result
|
||||
}
|
||||
```
|
||||
|
||||
If `inverse(x)` fails, the error will be returned again.
|
||||
|
||||
If `inverse(x)` succeedes, its value will be assigned to `result`.
|
||||
|
||||
|
||||
### Try/return
|
||||
|
||||
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.
|
||||
|
||||
```thp
|
||||
fun sample(Int x) -> String
|
||||
{
|
||||
val result = try inverse(x) return "0 was found"
|
||||
|
||||
if result == 2 { "2 was found" }
|
||||
else { "other number was found" }
|
||||
}
|
||||
```
|
||||
|
||||
If `inverse(x)` fails, `"0 was found"` will be returned.
|
||||
|
||||
If `inverse(x)` succeedes, its value will be assigned to `result`
|
||||
and the code will continue to execute normally.
|
||||
|
||||
|
||||
### Try/else
|
||||
|
||||
Try/else will run an expression and assign its value if `Ok`.
|
||||
Otherwise it will assign a second value.
|
||||
|
||||
```thp
|
||||
fun sample(Int x) -> Int
|
||||
{
|
||||
val result = try inverse(x) else 0.0
|
||||
|
||||
result
|
||||
}
|
||||
```
|
||||
|
||||
If `inverse(x)` fails, `0.0` will be assigned to `result`.
|
||||
|
||||
If `inverse(x)` succeedes, its value will be assigned to `result`.
|
||||
|
||||
|
||||
### Try/catch
|
||||
|
||||
Try/catch will run an expression and assign its value if `Ok`.
|
||||
Otherwise it will run a block of code, which will handle
|
||||
the error and assign a value as well.
|
||||
|
||||
```thp
|
||||
fun sample(Int x)
|
||||
{
|
||||
val result = try inverse(x)
|
||||
catch DivisionByZero e
|
||||
{
|
||||
// Handle `e`
|
||||
// ...
|
||||
|
||||
0.0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user