added: `Optional.try`
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 24 Apr 2023 01:43:48 +0000 (20:43 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 24 Apr 2023 01:43:48 +0000 (20:43 -0500)
core/container/optional.onyx

index 6da427af6f24007bb69a59c84428198f57cd3b0e..0afa32ff487f56a0d56ecab40a007ebe96309c10 100644 (file)
@@ -106,6 +106,58 @@ package core
         #unquote body;
     }
 
+    #doc """
+        Creates a scope that the `?` operator on an Optional type can
+        return to, instead of returning from the enclosing function.
+
+        Useful when chaining a bunch of operations that *could* fail,
+        while having a clean and easy escape hatch.
+
+            Optional.try() {
+                x := operation_1()?;
+                y := operation_2(x)?;
+                z := operation_3(x, y)?;
+                opreation_4(z);
+            }
+            println("Done");
+
+        In this example, if any of the operations fail, the execution
+        will cleanly go to `println` statement.
+
+        To know when something returned `None`, you can either use the second
+        parameter called `catch`, which is simply a block of code to be run.
+        Or you can use the return result from the function as so:
+        
+            // Sadly, cannot use the nicer syntax, `try() { ... }`
+            completed := Optional.try(#quote {
+                // ...
+            });
+    """
+    try :: macro (body: Code, catch: Code = #quote {}) -> bool {
+        //
+        // Using a 'do'-expression block to introduce a new
+        // 'return' location. This way, when the code in the `body`
+        // does a `return return`, it will target this do-block.
+        _ := do -> u32 {
+            //
+            // Insert the body of interest.
+            #unquote body;
+
+            //
+            // If execution makes it here, everything was successfuly
+            // and no `return return`s were encountered. Return true.
+            return return true;
+        };
+
+        #unquote catch;
+
+        //
+        // If execution makes it here, there was an unexpected early
+        // return. Return false to signal the caller of this.
+        return false;
+    }
+
+
     hash :: (o: ?$T/core.hash.Hashable) -> u32 {
         if !o.has_value do return 0;
         return core.hash.hash(o.value);