Skip to content
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

proposal: runtime: add parameters to recover to only return specific types #50424

Open
letian0805 opened this issue Jan 4, 2022 · 8 comments
Open
Labels
Projects
Milestone

Comments

@letian0805
Copy link

@letian0805 letian0805 commented Jan 4, 2022

The recover() function supports parameters in order to recover only expected exceptions.
For example:

defer func(){
	if err := recover(&MyError{}, &HelloError{}); err != nil {
		switch e := err.(type) {
		case *MyError:
			fmt.Println(e)
		case *HelloError:
			fmt.Println(e)
		}
	}
}

For now, we can handle it like this temporarily:

func Recover(expect ...interface{}) interface{} {
	if err := recover(); err != nil {
		if len(expect) == 0 {
			return err
		}
		rv1 := reflect.Indirect(reflect.ValueOf(err))
		for _, e := range expect {
			rv2 :=  reflect.Indirect(reflect.ValueOf(e))
			if rv1.Type() == rv2.Type() {
				return err
			}
		}
		panic(err)
	}
	return nil
}

However, each time Recover panic will increase the stack depth by 2. Therefore, a better way is to recover the specified exception by the runtime's recover function support parameters.

@gopherbot gopherbot added this to the Proposal milestone Jan 4, 2022
@letian0805 letian0805 changed the title proposal: affected/package: runtime proposal: affected/package: runtime, The recover function supports parameters in order to recover only expected exceptions Jan 4, 2022
@letian0805 letian0805 changed the title proposal: affected/package: runtime, The recover function supports parameters in order to recover only expected exceptions proposal: runtime: The recover function supports parameters in order to recover only expected exceptions Jan 4, 2022
@davecheney
Copy link
Contributor

@davecheney davecheney commented Jan 4, 2022

It sounds like you’re trying to implement try/catch style exception handling in Go.

@letian0805
Copy link
Author

@letian0805 letian0805 commented Jan 4, 2022

@davecheney Yes, but without breaking the syntax of Go.

@bcmills
Copy link
Member

@bcmills bcmills commented Jan 4, 2022

@ianlancetaylor ianlancetaylor changed the title proposal: runtime: The recover function supports parameters in order to recover only expected exceptions proposal: runtime: add parameters to recover to only return specific types Jan 4, 2022
@ianlancetaylor ianlancetaylor added this to Incoming in Proposals Jan 4, 2022
@carlmjohnson
Copy link
Contributor

@carlmjohnson carlmjohnson commented Jan 5, 2022

ISTM, this could basically almost be done as user function (baring bcmills's clever trick in #47653 (comment)), except that you can't quite rethrow the same panic as before if it turns out you didn't want to recover something. Why not fix that problem instead of adding a specific mechanism for types? Maybe have panicVal, trace := catch() and throw(panicVal, trace) or some other bikeshedded names. I like that panic now is type agnostic, and I don't think it's good to make a mechanism that only lets you distinguish by types and not by value.

@letian0805
Copy link
Author

@letian0805 letian0805 commented Jan 5, 2022

ISTM, this could basically almost be done as user function (baring bcmills's clever trick in #47653 (comment)), except that you can't quite rethrow the same panic as before if it turns out you didn't want to recover something. Why not fix that problem instead of adding a specific mechanism for types? Maybe have panicVal, trace := catch() and throw(panicVal, trace) or some other bikeshedded names. I like that panic now is type agnostic, and I don't think it's good to make a mechanism that only lets you distinguish by types and not by value.

@carlmjohnson Why not? Usually we have our own definition of error types, which are different from runtime exceptions.And recover(except ...interface{}) is compatible with existing code.

@beoran
Copy link

@beoran beoran commented Jan 5, 2022

The fact that even the standard library uses this kind of wrappers is good evidence that this is a good idea. It is also very simple and backwards compatible. I like it. What exactly is there against this idea?

@carlmjohnson
Copy link
Contributor

@carlmjohnson carlmjohnson commented Jan 5, 2022

I would also be fine with recover(true) returning two values and panic() accepting an optional trace. I specifically don't want types to be the sole mechanism for determining what to recover because it is very plausible that one would have a type like

type mypanic struct {
  ShouldRethrow bool
  Value any
}

Just being able to catch a particular type is fine, but what is really needed is the ability to say if val.ShouldRethrow { panic(val, trace) }.

In general, there is nothing I can think of in Go's core that work only in a type specific way as is proposed in this issue. make and new of course create specific types, but that's different from filtering inputs based on their type. errors.As and errors.Is aren't in Go's core but do work sort of like this (although they have carve outs for .As() and .Is() methods, so they aren't actually type specific if you create override methods), but in those cases you can do

type MyError struct {
   error
   ShouldFrobinicate bool
}

if myerr := MyError{}; errors.As(err, &myerr) && myerr.ShouldFrobinicate {
 // use myerr because it should be frobinicated …
}

// just use err as normal, even if it was a MyError…

So, my vote FWIW is to create a more general mechanism instead of a type specific one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Proposals
Incoming
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
7 participants