rust could need a better error handling system - very partial exception like - but different in handling
i don’t like the Result system for returning error because: -its an in-between of a simple c-like error-code, std::optional + user additional information -its still is possible to forget the handling of the result (like an error-code) -your be able to unwrap non-Err -Result does not follow zero-cost-abstraction rule -the Result is a big as the Union of all Result-Variants-Informations -Result teaches programmers to using simple errors or helps in building fat unions
for example C++ Exceptions does not suffer from these negatives - but heap allocation is done on throw and Exceptions do not stop on functions scope (shoot back through the stack) thats sometime not very nice
the idea could be just bullshit out of the box - but maybe its helpfull in any way
Example:
fn maybe_error(error: bool) -> Result<int, int> {
if error {
Err(1)
} else {
Ok(2)
}
}
fn main() {
{
//normal usage
match maybe_error(true) {
Ok(a) => println!("Ok {}", a),
Err(b) => println!("Err {}", b)
}
//maybe_error(true).unwrap(); // FAIL - only a runtime error - not compiltime-fail (due to the Result nature)
}
{
maybe_error(false).unwrap(); // "not" handled
}
}
the idea is to use some freaky sort of inline closure for error handling given to the Error “throwing” function by the compiler
fn maybe_error(error: bool /*hidden Error closure Stack Parameter*/ my_error, my_special_error, ... as many specialized Errors thrown, but not all everytime used)
if error {
fail my_error(1); --> fail calls hidden closure my_error
//-->return from maybe_error after error handled in main
} else {
//ok
}
fail my_special_error(data_on_heap_300kb, on_stack_200byte, on_stack_100byte); --> fail calls hidden Lambda my_special_error
//-->return from maybe_error after error handled in main
}
-----> the compiler constructs an hidden closure for every "catch" and attache them to the "throwing" function by "hidden" parameters (just on stack)
-----> the closure is called in context (no need to copy or heap the error-info - just stack) of maybe_error with main-scope access - as normal when the closure is defined in main-scope
fn main() {
int my_value = 10;
try maybe_error(true /*hidden error handling closures: &my_error, &my_special_error*/...) {
my_error ==> { forms the hidden closure
print("nr {0} {1}", my_error.nr, my_value);
}
special_error => { forms the hidden closure
print("nr {0} {1} {2} {3}", special_error.data, special_error.another_info, special_error.blub, my_value)
}
}
}
PROs -this way there is no need to create big errors that can handle every error-information the function can return -existence of error handling can be checked at compiletime (not the “qualitiy” of the handling itself) -cleaner interfaces
CONs -language change, “fail/try” or other special syntax for returning error and the try/match/closure behavior -functions needs to express to the compiler what exception types can be “thrown” -try/catch code-generation needs more analyse before -linking - i don’t know how that works in Rust - could be maybe problematik…
simplified-version / different signature idea
fn maybe_error(int value) -> int ==> fails blub(int x, int y),blib(str),blab(float,str,int) <-- becomes part of the signature (some sort of named closures)
{
if 1 ... fail blub(10,203.34);
return 20;
if 2 ... fail blib("hello");
if 3 ... fail blab(223.0, "hello",1+1);
return 10;
}
fn maybe_error2()
{
try
maybe_error
failed
blub(int, float) => { closure runs in context of mabye_error }
blib(str) => { closure runs in context of mabye_error }
blab(float, str, int) => { closure runs in context of mabye_error }
}
//functions with simple Result are still simple
fn maybe_error3() -> int fails (int)
{
if(xyz) fail(10);
return 20;
}
pros -feels like an clean symbios between the Result/match and “Exceptions” -no heap allocation -no copy (still in failing function context) -inline able if not in external lib -immutablity reserved cleanly -no fat Result-Types -no misuse of Result -clean error distinction -the error becomes part of the signature (happens also to the Result-Type - if not using int for everything) -keeps error local (like Result) - no “exception” like error spreading
cons -changes needed -(if that is a problem) does not behave like java,c#,c+±exceptions