Hi, I was wondering what the current best practices when using typed errors in your codebase. I currently use one error type per module which holds an integer to discriminate between variants. I then have implicit conversion for module error types that should be compatible. But somehow I still have problems with type inference / conversion. Here are some examples of what I am trying to do:
from std.builtin.globals import global_constant
@fieldwise_init
struct ErrorA(Equatable, ImplicitlyCopyable, Writable):
var _variant: Int
comptime UNKNOWN = ErrorA(_variant=0)
comptime foo = ErrorA(_variant=1)
@always_inline
def variant_name(self) -> StaticString:
comptime ERROR_A_VARIANT_NAMES: InlineArray[StaticString, 2] = [
"unknown",
"foo",
]
ref global_variant_names = global_constant[ERROR_A_VARIANT_NAMES]()
return global_variant_names[self._variant]
@always_inline
def msg(self) -> StaticString:
comptime ERROR_A_VARIANT_MESSAGES: InlineArray[StaticString, 2] = [
"Unknown error.",
"Foo!",
]
ref global_variant_messages = global_constant[
ERROR_A_VARIANT_MESSAGES
]()
return global_variant_messages[self._variant]
def write_to(self, mut writer: Some[Writer]):
writer.write("ErrorA.", self.variant_name(), ": ", self.msg())
@implicit
def __init__(out self, error_b: ErrorB):
self._variant = error_b._variant
@fieldwise_init
struct ErrorB(Equatable, ImplicitlyCopyable, Writable):
var _variant: Int
comptime UNKNOWN = ErrorB(_variant=0)
comptime bar = ErrorB(_variant=1)
@always_inline
def variant_name(self) -> StaticString:
comptime ERROR_B_VARIANT_NAMES: InlineArray[StaticString, 2] = [
"unknown",
"bar",
]
ref global_variant_names = global_constant[ERROR_B_VARIANT_NAMES]()
return global_variant_names[self._variant]
@always_inline
def msg(self) -> StaticString:
comptime ERROR_B_VARIANT_MESSAGES: InlineArray[StaticString, 2] = [
"Unknown error.",
"Bar!",
]
ref global_variant_messages = global_constant[
ERROR_B_VARIANT_MESSAGES
]()
return global_variant_messages[self._variant]
def write_to(self, mut writer: Some[Writer]):
writer.write("ErrorB.", self.variant_name(), ": ", self.msg())
@fieldwise_init
struct ContextManager(ImplicitlyCopyable):
var name: StaticString
@always_inline
def __enter__(mut self):
print("Entering ", self.name)
@always_inline
def __exit__(mut self):
print("Exiting ", self.name)
@always_inline
def __exit__[ErrType: Copyable](mut self, err: ErrType) -> Bool:
self.__exit__()
return False
def foo() raises ErrorA:
raise ErrorA.foo
# Unexpected compiler error: return expected at end of function with results
def bar() raises ErrorB -> Bool:
with ContextManager(name="bar"):
raise ErrorB.bar
return False
def foobar(call_foo: Bool) raises ErrorA:
with ContextManager(name="foobar"):
if call_foo:
foo()
else:
_ = bar()
def main() raises:
try:
with ContextManager(name="main"):
foobar(True)
foo()
bar()
except e:
print(e)
Thanks already for taking your time and giving feedback ![]()