aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2021-07-04 01:38:43 +0100
committergingerBill <bill@gingerbill.org>2021-07-04 01:38:43 +0100
commite8f2c5a48a7d5214925b9722b26270ca7eb3dd3c (patch)
treee35773f2cefc82fe82ee4944ba6a2a883a8c21eb /examples
parent1c76577918dc6bb7d3761501b0e137719c65accd (diff)
[Experimental] Add 'try' and `or_else' built-in procedures
Diffstat (limited to 'examples')
-rw-r--r--examples/demo/demo.odin141
1 files changed, 141 insertions, 0 deletions
diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin
index cbffc1956..5538d5b1c 100644
--- a/examples/demo/demo.odin
+++ b/examples/demo/demo.odin
@@ -1999,6 +1999,146 @@ relative_data_types :: proc() {
fmt.println(rel_slice[1]);
}
+try_and_or_else :: proc() {
+ fmt.println("\n#try(...) and or_else(...)");
+ // IMPORTANT NOTE: 'try' and 'or_else' are experimental features and subject to change/removal
+
+ Foo :: struct {};
+ Error :: enum {
+ None,
+ Something,
+ Whatever,
+ };
+
+ bar :: proc(ok: bool) -> (f: Foo, err: Error) {
+ if !ok {
+ err = .Something;
+ }
+ return;
+ }
+
+
+ try_return_value :: proc() -> Error {
+ // This is a common idiom, where the end value of an expression
+ // may not be 'nil' or may be 'false'
+ f0, err := bar(true);
+ if err != nil {
+ return err;
+ }
+ _ = f0;
+
+ // 'try' is a lovely shorthand that does this check automatically
+ // and returns early if necessary
+ f1 := try(bar(true));
+ fmt.println(#procedure);
+ fmt.println(f1);
+
+ f2 := try(bar(false));
+ fmt.println(#procedure);
+ fmt.println(f2);
+ return .None;
+ }
+
+ try_return_value2 :: proc() -> (i: int, err: Error) {
+ // 'try' will work within procedures with multiple return values
+ // However, the return values must be named
+ // 'try' effectively pops off the last value and checks it
+ // And then returns the rest of the values, meaning it works
+ // for as many return values as possible
+ i = 0;
+ f0, f0_err := bar(true);
+ if f0_err != nil {
+ err = f0_err;
+ return;
+ }
+ fmt.println(#procedure);
+ fmt.println(f0);
+
+ // The above can be translated into 'try'
+ i = 1;
+ f1 := try(bar(true));
+ fmt.println(#procedure);
+ fmt.println(f1);
+
+ i = 2;
+
+ f2 := try(bar(false));
+ fmt.println(#procedure);
+ fmt.println(f2);
+
+ i = 3;
+
+ return i, .None;
+ }
+
+ try_return_value4 :: proc() -> (i: int, j: f64, k: bool, err: Error) {
+ f := try(bar(false));
+ fmt.println(#procedure);
+ fmt.println(f);
+ return 123, 456, true, .None;
+ }
+
+
+ try_optional_ok :: proc() -> bool {
+ m: map[string]int;
+ /*
+ f1, ok := m["hellope"];
+ if !ok {
+ return false;
+ }
+ */
+ // 'try' equivalent
+ f2 := try(m["hellope"]);
+ fmt.println(f2);
+ return true;
+ }
+
+ {
+ // 'try' examples
+ err := try_return_value();
+ fmt.println(err);
+
+ ok := try_optional_ok();
+ fmt.println(ok);
+
+ i, err2 := try_return_value2();
+ fmt.println(i);
+ fmt.println(err2);
+
+ a, b, c, err4 := try_return_value4();
+ assert(a == 0 && b == 0 && c == false && err4 == .Something);
+ }
+ {
+ // 'or_else' does a similar value check as 'try' but instead of doing an
+ // early return, it will give a default value to be used instead
+
+ m: map[string]int;
+ i: int;
+ ok: bool;
+
+ if i, ok = m["hellope"]; !ok {
+ i = 123;
+ }
+ // The above can be mapped to 'or_else'
+ i = or_else(m["hellope"], 123);
+
+ assert(i == 123);
+ }
+ {
+ // 'or_else' can be used with type assertions too, as they
+ // have optional ok semantics
+ v: union{int, f64};
+ i: int;
+ i = or_else(v.(int), 123);
+ i = or_else(v.?, 123); // Type inference magic
+ assert(i == 123);
+
+ m: Maybe(int);
+ i = or_else(m.?, 456);
+ assert(i == 456);
+ }
+}
+
main :: proc() {
when true {
the_basics();
@@ -2031,5 +2171,6 @@ main :: proc() {
union_maybe();
explicit_context_definition();
relative_data_types();
+ try_and_or_else();
}
}