Way #1 is the only way that will work with Try/Catch syntax. Iād say itās the preferred way. However sometimes itās not sufficient when you want to deal with reporting information. In that case Iāve used error data structs as a side channel for building out messages.
I prefer to think about separating error handling and error reporting as two, often related, but different tasks. Zig errors are more about guiding the control flow.
Also there is a āfourthā way to create an error:
The caller probably needs to know that a validation error has occurred, so returning a true Zig error for that (#1) is needed. True errors are used in Zig to perform control flow in the caller.
For just reporting an error message, you may not need to return the message field to the caller. You could log it immediately instead, for example.
But if the caller needs the message or other information about the error, then it can be returned in a separate āoutā parameter, in addition to returning the error. The caller would catch the error, switch on the error type, and then use the message returned in this extra parameter. For example, this extra parameter could be type ?*ValidationInfo, where ValidationInfo contains the message. By making it an optional pointer, the caller can pass null if the additional info is not needed.
what do you like about it? what is it trying to accomplish? does it do that? i think if you had clear answers to those questions, our feedback might be less useful.
Itās great that youāve learned how to use comptime, anytype and anyerror. Youāll need that skill.
For this use case, I wonder whether anytype and anyerror are really needed. It is best to avoid them, if possible, because they reduce code readability.
I see in this use case that the specific error is not needed by the caller (in main), since the error details are logged before returning. What will the caller do when an error is returned, in a real application? Will the application need to switch on the error code? If so, how would it do that?
What I want to accomplish is I can generate error messages that can be reused in other code/file and can add additional context if needed. Iām not sure if it accomplish it fully yet ;(
Iām myself not sure if that is the correct approach, because Iām still new in Zig. Here is what Iām trying to do (please correct whether anytype, anyerror, etc is needed in this case)
Iām trying to create prototype for struct field validation library, where the rule is centralized in the declaration. The caller doesnāt know what is the validation rule. It is to avoid potential inconsistency when there are many callers. The value is protected under Validated struct to prevent accidental mutate without going through the validation rules. The user can specify specific error message for each validation, then the error will be propagated until it eventually be consumed in a logging and/or a http response. The tryCatch method is just my syntatic sugar to print the error, but not part of the library, the real usage will just place try keyword to propagate the error. The library will expand to email validation, string length min and max validation, is a string contains certain character like it must contains combination of char number and symbol, no whitespace validation, sanitize or block certain character, datetime validation like the datetime can not be the past, etc
Edit : The tryCatch method will still be used by removing the println, as a syntatic sugar to add dynamic error message if the user need to add dynamic message
In general I also like to refrain from coupling error handling and reporting together to much. Also zig has some nice error return traces so it is often easier to just use them. See the language reference.
The problem with your current approach (with the tryCatch) is that this information is lost because you just return some zeroed memory on error. This could be the right call depending on what youāre doing but I would just let the caller handle the error as they want to.
If you want to pursue this further you could also do something like this. Of course just to illustrate
You could also add other parameters to logError to print something different depending on further information. But I personally wouldnāt do that because you tangle everything together into one big ball of mud.
Usually when you want to log a warning, or an error, or whatever, you have more information and in particular more context at the callsite. Then you can write a good message for the user with some more information which is nicer and could, for instance, maybe help you find bugs easier.
i donāt understand errors and errorsets too well.
And this looks even more obscure to me. const err = (error{FileNotFound}).FileNotFound;
Now I really donāt know anymore what is what. But I am tiredā¦
I was just wondering about that statement earlier. It is indeedpossible I sawā¦
The short answer is Yes. error.FileNotFound creates an error set with one error, FileNotFound, and then it returns that one error.
You use an error set when declaring a function return type, since an error union is a union of an error set and another value. You need individual errors when you return them or switch on them. The doc explains it in more detail when you feel like studying.
The key value of the first approach lies in its ability to trigger errdefer when returning. If you believe that in your code there are critical states that need to be released or rolled back when a specific error occurs, then this error must be defined using an error union.
zigs errors are meant to fulfil what was manually done in c with integer error codes. That is to say, zigs error system is for control flow, for code reacting to errors.
If you want/need to propagate other information, you should use a separate mechanism. But you should avoid replacing zigs error system, as it provides great ergonomics for dealing with errors. Both can exist together and compliment each other.
These two blog posts are a great start to explore these concepts: