#error handling

1 messages · Page 1 of 1 (latest)

wise shell
#

I'm working on runtime errors in a toy language I'm making. Is this an okay way of handling errors?

// error.zig

pub const RuntimeErrorPayload = union(enum) {
    unexpected_type: struct { ... },
    undeclared_identifier: []const u8
};

pub const RuntimeError = error {
    Error
};

// Vm.zig

err: ?RuntimeErrorPayload,

pub fn setError(self: *Vm, err: RuntimeErrorPayload) RuntimeError!void {
    if (self.err != null) {
        self.err = err;
    }
    return RuntimeError.Error;
}

I would then be able to call try vn.setError(...) whenever a runtime exception occurs and that would be propagated back to the main method where I could print out what the error was and where it occured and such

polar vapor
#

Like in C++/Python/Java

wise shell
#

in my language or in zig?

polar vapor
#

In your language

wise shell
#

in my language any error will just end the program

#

because of the nature of the language's application, any error is fatal

polar vapor
#

Ah, I see, makes sense

#

Yeah I guess it's fine. Not too much code to review

wise shell
#

im just wondering if this is an okay way to handle errors in zig

polar vapor
#

Yes; note that you will need to use try on every function that can potentially call setError

feral kayak
#

Sadly zig doesn't allow payloads inside errors, only error codes. I really hope it makes it way into the langage. You need to store the error payload elsewhere.

wise shell
polar vapor
wise shell
#

yep, thats what my plan was. Thank you!

polar vapor
wise shell
#

Is it weird that the error set just has Error? is there a more idiomatic name>?

polar vapor
#

But note that this is a generic name and some other function could return this, not from your code.

wise shell
#

I wanted something a bit more type-safe though

polar vapor
#

Well in that case I think you can only make the error set as you did; you can consider naming the set something else and the particular error RuntimeError, for example:

pub const FejiLangErrors = error {
    RuntimeError,
};
#

Maybe you will need another error in the same set that will mean something else.

wise shell
#

good point, thank you!

mild cobalt
wise shell
#

I don't like the way I handle errors in rust with the result type, i feel like i can do some pretty lazy things with it

#

i much prefer how zig does it

mild cobalt
#

zig's errors are kinda unique in that they don't say anything about how to report errors to the user

#

they're purely for control flow

#

you can detect "an error occurred", and you can do different things based on which error occurred, but they don't contain any data other than what's required for control flow purposes

polar vapor
#

I find that a bit funny

wise shell
#

Yea I really like that mentality. I sort of became disenamored with errors as values from rust & go, but its really nice in zig

feral kayak
#

it's just so impractical to use: you need to pass an extra parameter to each function, on top of 'trying' everywhere.

mild cobalt
#

a) no you don't, you can put it on a struct
b) there's already a bunch of things like that, eg. allocators, writers, temporary buffers, and soon std.Io

polar vapor
wise shell
#

I just finished writing a somewhat big project in C and the macros I had for handling errors were egregious 😭. despite that though I enjoyed it more than rust

polar vapor
polar vapor
mild cobalt
#

from the user's perspective, they simply check zoir.hasCompileErrors() after calling generate, and don't need to worry about diagnostics whatsoever

#

and the ZonGen code can use try for quickly passing errors up the stack, if it wants to, as long as it catches those errors and stores them before returning

#

(ZonGen doesn't actually seem to do that much long-distance control flow with errors, but other parts of the compiler, such as Sema, very much do)

wise shell
#

For applications, is it okay to let the error be inferred when returning, or should you always specify what error set you're returning? E.g. the difference between fn foo() !void or fn foo() Allocator.Error!void

mild cobalt
#

specifying an explicit error set can also catch bugs in cases where you only want certain types of error to escape the function, eg. if you're handling all your IO errors, but you still want to return error.OutOfMemory

winged iris
mild cobalt
#

nah

#

it depends how you structure your error data, but you either just clear it if it already exists, or append to it

#

eg. for a compiler, you can store an array of error messages, and append each time