From a449ea108544eaa502723436a3496df2e06fd052 Mon Sep 17 00:00:00 2001 From: Araozu Date: Sun, 28 Apr 2024 22:05:04 -0500 Subject: [PATCH] Improve docs on try/exceptions --- public/css/pages.css | 11 ++ src/pages/learn/error-handling/try.md | 169 ++++++++++++++++++++------ 2 files changed, 146 insertions(+), 34 deletions(-) diff --git a/public/css/pages.css b/public/css/pages.css index e8a17e4..3e8fe0d 100644 --- a/public/css/pages.css +++ b/public/css/pages.css @@ -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; diff --git a/src/pages/learn/error-handling/try.md b/src/pages/learn/error-handling/try.md index 0c85a71..611c435 100644 --- a/src/pages/learn/error-handling/try.md +++ b/src/pages/learn/error-handling/try.md @@ -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 + } +} ```