gingerBill

  • Home
  • Articles
  • Podcast
  • Odin
  • Subscribe

The Value Propagation Experiment Part 2

2021-09-06

**[Originally from a Twitter Thread]**

I have revisited The Value Propagation Experiment and have come to a different conclusion as to why it failed and how I recovered it.

The recovery work has been merged into master now with this PR: https://github.com/odin-lang/Odin/pull/1082

I think there were three things which were confusing which make it look like a failure of an experiment:

  • try was a confusing name for what the semantics were.
  • try as a prefix was the wrong place.
  • Unifying try with try else was a bad idea for many reasons.

Changes in the PR:

  • Built-in or_else procedure became a binary operator instead (meaning it became a keyword).
  • or_return was added as a keyword.
  • or_return became a suffix-operator/atom-expression.
if i, ok = m["hellope"] !ok { i = 123 }

becomes

i = m["hellope"] or_else 123
if err = foo(); err != nil { return }

becomes

foo() or_return

Most people understood what the purpose and semantics or_else pretty intuitively but many were very confused regarding the semantics of try. My conclusion was that the keyword-name and positioning were the main culprits for that.

Another aspect which I stated in the original article was that I thought the construct was not as common as I originally thought. And for my codebases (including most of Odin’s core library), this was true. However it was false for many codebases, including the new core:math/big.

In the core:math/big package alone, or_return was able to replace 350+ instances of if err != nil { return } idioms.

The more C-like a library is in terms of design, the more it required this or_return construct. It appears that when a package needs it, it REALLY needs it.

When this correction was made, there were 350+ instances of or_return in a ~3900 LOC is ~9% of (non-blank) lines of code. That’s a useful construct for definite.

Another (smaller) package that found or_return useful was the new core:encoding/hxa, which is an Odin native implementation of @quelsolaar’s HxA format. https://github.com/quelsolaar/HxA

The entire implementation for reading and writing is 500 LOC, of which there are 32 or_returns.

I do believe that my general hypotheses are still correct regarding exception-like error value handling. The main points being:

  • Error value propagation ACROSS library boundaries
  • Degenerate states due to type erasure or automatic inference
  • Cultural lack of partial success states

The most important one is the degenerate state issue, where all values can degenerate to a single type. It appears that you and many others pretty much only want to know if there was an error value or not and then pass that up the stack, writing your code as if it was purely the happy path and then handling any error value. Contrasting with Go, Go a built-in concept of an error interface, and all error values degenerate to this interface. In practice from what I have seen of many Go programmers, most people just don’t handle error values and just pass them up the stack to a very high place and then pretty much handle any error state as they are all the same degenerate value: “error or not”. This is now equivalent to a fancy boolean.


I do hope that this addition of or_return does aid a lot of people when making projects and designing packages.

It does appear to be very useful already for many of the core library package developers for Odin.

© 2007–2024 Ginger Bill