V: Solve error() & panic() "dualism"

Created on 18 Sep 2019  路  12Comments  路  Source: vlang/v

V version:
latest from git

OS:
any

What did you do?
Used "optionals" as return types.

What did you expect to see?
Sane, logical and simple behavior.

What did you see instead?
Weird inconsistency, bloat, etc.

Ideas, suggestions, clarifications, ...
Why do does this "dualism" of error() and panic() exist? Doesn't panic( arg ) behave just like return error( arg ), but being differently type checked thus leading to unnecessary issues?

If panic() doesn't bring anything new, but offers way less flexibility than return error( ... ), then I'd definitely advocate for removal of panic() as it's confusing, leads to type checking issues and doesn't bring anything except for complexity.

Feature Request Discussion

Most helpful comment

Doing that by recovering in a higher scope to the one locking the mutex is messy.

From my experience I'd say it's vice versa (this concept is widely used in Dao and Go etc. and proved way better than any other concept) - especially if function declaration can be done inside of another function declaration. If "recovering in a higher scope" is the only contra-argument, then I'd say it actually confirms its robustness and viability.

Other concepts (including RAII) are hard to optimize if done properly and always clutter the language (this second thing is less important than the optimization issue IMHO though). But V is a simple language, so any complicated concepts are IMHO not a good fit.

All 12 comments

panic() is completely different from error()

panic stops the execution of the entire program, error() is for handling Result types.

What's the real use case of panic() then? I mean, both panic() and error() require the function to return an optional, right? So what is really the practical difference between return error() and panic()?

panic() doesn't require a function to return an optional. It's pretty much to exit the program when you encounter an unrecoverable error. When you can't continue further.
error() is for handling Result types as alex said, and errors can be recovered from, panic can not. You could detect an error and then do another action based one it.

and errors can be recovered from, panic can not.

True, but in the future it'll be possible to recover from panics, just like in Go.

@dumblob I'll make it more clear in the docs.

True, but in the future it'll be possible to recover from panics, just like in Go.

Well, this is what doesn't make much sense to me - actually having "exceptions" in the function interface is what makes V so good in writing correct programs. But by introducing recover for panic all this endeavor will slip in the languages mainstream and there won't be much to praise V for. In this case I would plead you to think about this twice before you'll allow recovery from panics.

How I see it, V has an exception-like mechanism - it's called "optionals", uses return error() in the callee and ) or { ... } in the caller. If there is no ) or { ... }, then the error gets automatically propagated (the compiler enforces the caller to also return an optional even though the return type is does not match the one of the callee). It's easy to grasp, super neat to use, super clear in syntax, super fast in runtime, super easily implemented. It does basically everything exceptions do in other languages, but better.

What is panic() good for then? panic() will have super complex semantics when it comes to parallelism, concurrency etc., it won't offer absolutely anything more than the above described error() mechanism, it'll probably bloat V with yet another syntax for recovery of panics, it'll make exceptions totally hidden, it won't be compatible with JavaScript and especially not with WebAssembly, and so on and on. Btw. there is nothing like "unrecoverable error" - it's each time very use case specific and I would actually argue it's vice versa - each error is recoverable, but sometimes the programmer just intentionally explicitly doesn't want to recover for whatever reason.

I have to admit, I'm totally lost by hearing about panic() now after all the hopes for a practical language with finally clear interfaces for exceptions (not the bloat throws ... from Java or val, err := in Go or having them totally hidden or any other known exceptions implementation).

@medvednikov oops, I just woke up.. didn't mean to close it :D, yeah recover was a bad choice of words, since recovering from exceptions is a thing :D Sometimes you need to be able to recover, like if your calling a function you didn't write which panics, but you cant have your program exiting. Something running in a thread might even panic then your up the creek, especially if you keeping count or haven't unlocked a mutex, or any number of nasty things could happen. Of course your really should try not to design your programs like that, sometimes you don't have a choice.

@joe-conigliaro this must be a misunderstanding, because I totally agree with your last comment with no exceptions :wink:.

I guess the misunderstanding is on my side in how error() is meant to work. From my current understanding it works like this:

  1. error() can be used only in a function F returning an optional (i.e. type preceded by ?); if this doesn't hold, then the compiler will error out and won't allow compilation of such program under any circumstances
  2. when function F2 calls a function F (disregarding whether F2 uses or throws away the returned value from F) there are only two options:

    1. either there is an or { } clause right after the call to F in which case any error from F gets caught and nothing special happens (i.e. the golang val, err := func1( ... ) semantics but nicer)

    2. or there is no or { } clause right after the call to F in which case the compiler inserts or { return err } automatically (but preserves the error origin for better debugging traces) effectively behaving like in (1) - i.e. in runtime immediately returns from F2 the unhandled error and in compile time enforces that F2 also returns an optional (i.e. panic()/raise/... semantics but nicer)

Do I understand everything correctly?

@dumblob your idea about unrecoverable panics is interesting. I'll think about it.

Do I understand everything correctly?

The compiler does not insert or { return err } automatically.

The compiler does not insert or { return err } automatically.

@medvednikov the compiler could take the "pessimistic" approach by default and expect any code-block potentially to fail (let it be a RAM failure, where some bits shift w/o ECC - I know normally this shall be handled by the Kernel) then it would be safe to add or { return err } virtually everywhere where a return value is expected - but perhaps this is not realistic scenario anyway

And for panic() I think better would be something like os.exit() with optional err_code/msg

Sometimes you need to be able to recover... Something running in a thread might even panic then your up the creek, especially if you keeping count or haven't unlocked a mutex

That's why V should support RAII, so the mutex automatically unlocks before the panic. Doing that by recovering in a higher scope to the one locking the mutex is messy.

I think V should allow intercepting a panic, reacting to it in a callback but then the thread that panicked should end. The parent thread can inspect any data written from the panic callback and then restart the thread spawn a replacement thread if desired.

Doing that by recovering in a higher scope to the one locking the mutex is messy.

From my experience I'd say it's vice versa (this concept is widely used in Dao and Go etc. and proved way better than any other concept) - especially if function declaration can be done inside of another function declaration. If "recovering in a higher scope" is the only contra-argument, then I'd say it actually confirms its robustness and viability.

Other concepts (including RAII) are hard to optimize if done properly and always clutter the language (this second thing is less important than the optimization issue IMHO though). But V is a simple language, so any complicated concepts are IMHO not a good fit.

Sometimes you need to be able to recover... Something running in a thread might even panic then your up the creek, especially if you keeping count or haven't unlocked a mutex

That's why V should support RAII, so the mutex automatically unlocks before the panic. Doing that by recovering in a higher scope to the one locking the mutex is messy.

I think V should allow intercepting a panic, reacting to it in a callback but then the thread that panicked should end. The parent thread can inspect any data written from the panic callback and then ~restart the thread~ spawn a replacement thread if desired.

So you're essentially saying that one should be able to observe a panic, but not halt it?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ArcDrake picture ArcDrake  路  3Comments

markgraydev picture markgraydev  路  3Comments

oleg-kachan picture oleg-kachan  路  3Comments

elimisteve picture elimisteve  路  3Comments

radare picture radare  路  3Comments