Replies: 15 comments 2 replies
-
How does not having exceptions make Odin into Go? While I do agree that the Go way of handling errors is less than optimal, as it tends to produce a lot of duplicated error handling code, I beleive it is far superior to exceptions. My ideal error handling is the use of a "Result" type representing either the value of a computation if succesful, or an error message/object if not succesful (like the method commonly used in Rust). I've been out of the loop on Odin for a bit, so I am not sure if Odin has the facilities for such a type. |
Beta Was this translation helpful? Give feedback.
-
Run-time exceptions are a higher-level construct that does not fit into the vision of Odin. Also, adding a feature just because it would make Odin more popular is a terrible reason. If we just added for popularity we would also for example have GC. |
Beta Was this translation helpful? Give feedback.
-
@kiljacken There isn't anything in Odin defining the error handling, that's still up to the individual programmer. |
Beta Was this translation helpful? Give feedback.
-
My suggestion is that if there is something builtin for error handling, it should just be purely syntactic sugar. In C, usually I have a macro called A macro/metaprogramming system or even a specific error handler system could alleviate the problem. For example (made up syntax):
And it will be rewritten into:
Some type guard/check might be needed so that you can use two handlers in the same This is basically the idea of Haskell's monad but modified for an imperative language. This is explicit ( |
Beta Was this translation helpful? Give feedback.
-
I suggest taking a look at the way Rust handles errors. It is eloquent,
integrated into the type system and makes the user constantly aware of what
can go wrong.
…On Mon, Sep 3, 2018 at 9:22 AM Bach Le ***@***.***> wrote:
I've been lurking for quite a while, my suggestion is that if there is
something builtin for error handling, it should just be purely syntactic
sugar.
In C, usually I have a macro called SOMETHING_CHECK e.g: GFX_CHECK and
call it like: SOMETHING_CHECK(call_that_may_fail(...)) and it works fine
albeit, a bit verbose but still better than the Go way of copy and paste
that if statement.
A macro/metaprogramming system or even a specific error handler system
could alleviate the problem. For example (made up syntax):
with my_error_handler {
a := call_that_can_fail();
b := another_call(a);
}
And it will be rewritten into:
my_error_handler(a, call_that_can_fail());
my_error_handler(b, another_call(a));
my_error_handler can then be a macro that check the return type, decides
to whether return early or continue with execution.
Some type guard/check might be needed so that you can use two handlers in
the same with statement for example.
This is basically the idea of Haskell's monad but modified for an
imperative language.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#256 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AIAzh0GJH-SR88rntADpQKPIYOKFusHyks5uXNisgaJpZM4WWvSC>
.
|
Beta Was this translation helpful? Give feedback.
-
@bullno1 Odin has the option for multiple return values so how would that system know which of the parameters to use for it's checking? + some function might use different values for error codes, ints, enums, bools etc.. |
Beta Was this translation helpful? Give feedback.
-
There will never be software exceptions in the traditional sense. I hate the entire philosophy behind the concept. Go does have exceptions with the defer, panic, recover approach. They are weird on purpose. Odin could have something similar for exceptional cases. You can the exact same semantics as a try except block by using a switch in statement. The same is true in Go. The difference is that the stack does not need to be unwinded and it's structural control flow. Odin has discriminated unions, enums, bit sets, distinct type definitions, any type, and more. Odin also have multiple return values. Use the type system to your advantage. I do hate how most languages handle "errors". Treat errors like any other piece of code. Handle errors there and then and don't pass them up the stack. You make your mess; you clean it. |
Beta Was this translation helpful? Give feedback.
-
I get the feeling that most people in this discussion have a fairly surface-level knowledge of Odin's syntax. This isn't an insult, I'm just saying there is far less of a problem than some of you seem to think. Odin has multiple returns as well as a declaration & condition variant of if bytes, ok := os.read_entire_file("filename.ext"); ok {
fmt.println(string(bytes));
}
else {
// handle failure
}
// you can also ignore returns
bytes, _ := os.read_entire_file("filename.ext"); // `_` is a value-sink; anything written to it vanishes, it cannot be read from You can also use types like this:
or this:
as return values. This is a powerful approach and gives the programmer total control of how to handle errors, as well as making the potential for an error to occur completely explicit in a procedure's prototype. Anything more than this - involving error handlers, runtime exceptions and/or try/catch - serves to take back control from the programmer and make the presence of errors a complete mystery. It makes code less readable and, in fact, more error-prone. The only "positive," if you can call it that, is that it "hides" error-handling and allows the programmer to program as though errors don't exist, passing on responsibility from libraries or worse, crashing a user's program unnecessarily. This is just laziness, as far as I can see (and you can be lazy explicitly with There are numerous ways to "manufacture" your own error-handling system in Odin - Bill mentioned the tagged unions, which can be |
Beta Was this translation helpful? Give feedback.
-
To expand on what I mean by this statement:
Python: try:
x = foo()
except ValueError as e:
pass # Handle error
except BarError as e:
pass # Handle error
except (BazError, PlopError) as e:
pass # Handle errors Odin: Error :: union {
ValueError,
BarError,
BazError,
PlopError,
}
foo :: proc() -> (Value_Type, Error) { ... }
x, err := foo();
switch e in err {
case ValueError:
// Handle error
case BarError:
// Handle error
case BazError, PlopError:
// Handle errors
} The semantics are very similar in this case however the control flow is completely different. In the exceptions case (shown with Python), you enclose a block of code and catch any exceptions that have been raised. In the return value case (shown with Odin), you test the return value explicitly from the call. In both cases, a "catch all" is possible: try:
x = foo()
except Exception:
pass # An error has happened Odin: x, err := foo();
if err != nil {
// An error has happened
} One "advantage" many people like with exceptions is the ability to catch any error from a block of code: try:
x = foo()
y = bar(x)
z = baz(y)
except SomeError as e:
pass I personally see this as a huge vice, rather than a virtue. From reading the code, you cannot know where the error comes from. Return values are explicit about this and you know exactly what and where has caused the error. One of the consequences of exceptions is that errors can be raised anywhere and caught anywhere. This means that the culture of pass the error up the stack for "someone else" to handle. I hate this culture and I do not want to encourage it at the language level. Handle errors there and then and don't pass them up the stack. You make your mess; you clean it. Go's built-in if err != nil {
return nil, err
} From what I have read, most people's complaints about the Go error handling system is the I hope this has cleared up a lot of the questions regarding Odin's take on error handling. I think error handling ought to be treated like any other piece of code.
P.S. If you really want "exceptions", you can |
Beta Was this translation helpful? Give feedback.
-
Reduce the surface area of where errors can occur inside your code. For example, if you need to open a file, and you're not sure it exists, and want to handle failure, don't structure your code such that this function is 10 levels down a call stack. Define types that can embed "errors" and make your code work with these types.
I don't think that's what people like about exceptions. They like about it that they can ignore error cases while writing code; for example, they can write something like this:
if the file doesn't exist, none of your code has to worry about that! You pretend everything succeeds in most of your code, and then just dedicate a small portion of the most top level function to handle "exceptions". In my experience this creates sloppy programs; hides errors, makes them hard to debug. It's also why a lot of error messages in a lot of program are confusing: it's because the programmer himself cannot know what the error is at the exception catch site; they best they can do is say "looks like something went wrong". |
Beta Was this translation helpful? Give feedback.
-
That is a completely separate aspect. That is still possible with a switch statement and using the default case. |
Beta Was this translation helpful? Give feedback.
-
That's still explicitly checking for an error. I mean not even checking if an error has occurred. Say you have procedure A that calls B that calls C that calls D that calls E that calls F.
Only That's what people like about exception throwing. It's also why people complain about this in Go:
Because in Python and other languages this step is automatic, but in Go and languages without exception you have to explicitly emulate exception throwing for every call using the |
Beta Was this translation helpful? Give feedback.
-
I dislike error propagation which is implicitly passing the error up the stack. People like being lazy, so don't give them more opportunity to be so.
And that's why I like Go, because error handling is explicit. The issue I have is that people just return the error and pass it up the stack again. It doesn't matter how the errors are implemented (values or exception) in the case, it's the error propagation. |
Beta Was this translation helpful? Give feedback.
-
Does In detail, any open database transactions are rolled back, the error info written out to a log (or saved in the database even) perhaps some global variables cleared, maybe a 'rollback_session' stored procedure gets called, sleep for a few seconds and restart. Preferably without restarting the whole process and losing details (like network connections to a client and which session needs to be rolled back!) |
Beta Was this translation helpful? Give feedback.
-
Please do not turn Odin into second Go. Add Try/Except(or Catch). I think that Odin will become more popular than now.
Beta Was this translation helpful? Give feedback.
All reactions