Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Solve error() & panic() "dualism" #2030

Closed
dumblob opened this issue Sep 18, 2019 · 18 comments
Closed

Solve error() & panic() "dualism" #2030

dumblob opened this issue Sep 18, 2019 · 18 comments
Labels
Feature Request This issue is made to request a feature.

Comments

@dumblob
Copy link
Contributor

dumblob commented Sep 18, 2019

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.

@dumblob dumblob added the Bug This tag is applied to issues which reports bugs. label Sep 18, 2019
@medvednikov
Copy link
Member

panic() is completely different from error()

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

@dumblob
Copy link
Contributor Author

dumblob commented Sep 18, 2019

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()?

@joe-conigliaro
Copy link
Member

joe-conigliaro commented Sep 18, 2019

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.

@medvednikov
Copy link
Member

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.

@dumblob
Copy link
Contributor Author

dumblob commented Sep 18, 2019

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).

@joe-conigliaro
Copy link
Member

joe-conigliaro commented Sep 18, 2019

@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.

@dumblob
Copy link
Contributor Author

dumblob commented Sep 19, 2019

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

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?

@medvednikov
Copy link
Member

@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.

@gslicer
Copy link

gslicer commented Sep 24, 2019

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

@chanbakjsd chanbakjsd added discussion Feature Request This issue is made to request a feature. and removed Bug This tag is applied to issues which reports bugs. labels Sep 28, 2019
@ntrel
Copy link
Contributor

ntrel commented Nov 4, 2019

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.

@dumblob
Copy link
Contributor Author

dumblob commented Nov 17, 2019

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.

@Richiban
Copy link

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?

@dedesite
Copy link
Contributor

Found this discussion interesting, but wonder how you could avoid panic() to stop execution in some cases.

For example, let's say you try to access a element outside an array :

a := [1, 2, 3]
println(a[3])

The [] does not return an optional (maybe it should ? :)) so there is no way to let the program continue without breaking things.
Do you have some ideas @dumblob ?

@Delta456
Copy link
Member

you can now do a[3] or {} to solve this :)

@dedesite
Copy link
Contributor

you can now do a[3] or {} to solve this :)

Great, but if you don't do it, panic is called right ? So or { usage is not mandatory no ?

What I wanted to know is what would @dumblob suggest to completly remove panic usage ?

@dumblob
Copy link
Contributor Author

dumblob commented Feb 12, 2021

The [] does not return an optional (maybe it should ? :)) so there is no way to let the program continue without breaking things.

As @Delta456 points out, it actually does return an optional (but if I'm not mistaken, unlike "standard" optional return values, this case is an exception and the handling as optional is not being enforced and thus leaving out or {} doesn't produce any compile time error - in that case I'm not sure why I've seen a[3]! in some V code).

If an optional won't work, then there is a simple and clear (well defined) construct - namely runtime assert which covers all these remaining cases.

@dedesite
Copy link
Contributor

If an optional won't work, then there is a simple and clear (well defined) construct - namely runtime assert which covers all these remaining cases.

As I see it, panic() implementation is quite similar to what assert does, no ? So I don't see what is such a big problem with panic, but I get that if they behave the same, assert should be use.

@dumblob
Copy link
Contributor Author

dumblob commented Feb 15, 2021

As I see it, panic() implementation is quite similar to what assert does, no ? So I don't see what is such a big problem with panic, but I get that if they behave the same, assert should be use.

First of all, panic() is still by far not finished - I've understood the goal is to make it behave similarly to panic() in Go. But that's a huge undertaking - read further.

It's nearly impossible to make panic() work safely with threading in V (moreover it's extremely hard to judge about what the code does) - all stack unwinding with all recursive defer{}s and locks etc. called in right order without violating anything coused by the initial panic()... (actually I'd guess it's provably impossible to do it right without introducing additional semantics and constructs to V, but that's just my feeling based on experience with C++).

Second, V has the there is only one way of doing things mantra which doesn't work here.

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
Feature Request This issue is made to request a feature.
Projects
None yet
Development

No branches or pull requests

9 participants