I prefer the ML way, which your stackoverflow doesn't consider. Rust, which borrows heavily from ocaml, does not have or use exceptions. You can do method chaining, and you can simply handle errors inline. How you do that is flexible, depending on your need. The error can be handled by the calling function using a simple question mark, like
let bar = foo()?.bar()?
Or you can transform the error or the resulting value using e.g.
let bar = foo().map(|v| v.bar())?
If your type implements Default (basically all primitive types do, and structs can simply derive it) then you can just say to return the default value if any errors are encountered:
let bar = foo().map(|v| v.bar()).unwrap_or_default()
So suppose bar() returns either a string or an error, in the above, bar would just be an empty string. Or, you can simply have it panic if either fails:
let bar = foo().unwrap().bar().unwrap()
Or
let bar = foo().expect("foo failed").bar().expect("bar failed")
But actually this isn't even what I was talking about. Go in general is very boilerplate-y, and GP demonstrated a good example of that. Rather, see this:
https://blog.janestreet.com/ef...
In Go, some of this isn't even possible to achieve, and the examples you can do in Go require a lot more code. And you'll have a very hard time trying to come up with an example in the other direction. Here's also a rust psuedocode example I'm curious to see how you handle in Go:
(slashdot seems to be hostile to any attmempt at indenting)
let file_text = file
.open()
.await
.map_err(|e| format!("couldn't open file because {e}"))?
.read_text()
.await
.map_err(|e| format!("couldn't read text because {e}"))?;
Where open() and read_text() are async functions. This code does not panic, and even uses the idiomatic Go approach of all errors as strings. The only way I know of to do this in Go involves a lot of boilerplate involving goroutines, usually channels, tuples and if err != nil checks. We'll also pretend that Go has a concept of a yield point.