diff options
| author | gingerBill <bill@gingerbill.org> | 2021-07-04 01:38:43 +0100 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2021-07-04 01:38:43 +0100 |
| commit | e8f2c5a48a7d5214925b9722b26270ca7eb3dd3c (patch) | |
| tree | e35773f2cefc82fe82ee4944ba6a2a883a8c21eb /examples | |
| parent | 1c76577918dc6bb7d3761501b0e137719c65accd (diff) | |
[Experimental] Add 'try' and `or_else' built-in procedures
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/demo/demo.odin | 141 |
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(); } } |