Why does panic(nil) return nil to recover?

641 views
Skip to first unread message

Brendan Tracey

unread,
Jan 22, 2014, 3:04:09 PM1/22/14
to golan...@googlegroups.com
I just had an encounter with issue 6546, and I was curious about the rationale for panic(nil) returning nil to recover. It would seem to me that the desired behavior is "the recover error is non-nil if the code panicked". panic(nil) does in fact panic, so why not signal so to recover? 

Jan Mercl

unread,
Jan 22, 2014, 3:13:29 PM1/22/14
to Brendan Tracey, golang-nuts
See http://golang.org/ref/spec#Handling_panics

""""
The return value of recover is nil if any of the following conditions holds:

panic's argument was nil;
the goroutine is not panicking;
recover was not called directly by a deferred function.
""""

IOW, the behavior of panic(nil) vs recover() result is strictly
specified - and thus expected. Also mind the Go 1 compatibility
promise.

BTW: The specified behavior of panic(nil) is _very_ useful. One can
also think about it as: recover simply returns what the argument to a
possible panic was, no special cases.

-j

Brendan Tracey

unread,
Jan 22, 2014, 4:31:58 PM1/22/14
to Jan Mercl, golang-nuts

On Jan 22, 2014, at 12:13 PM, Jan Mercl <0xj...@gmail.com> wrote:

> On Wed, Jan 22, 2014 at 9:04 PM, Brendan Tracey
> <tracey....@gmail.com> wrote:
>> I just had an encounter with issue 6546, and I was curious about the
>> rationale for panic(nil) returning nil to recover. It would seem to me that
>> the desired behavior is "the recover error is non-nil if the code panicked".
>> panic(nil) does in fact panic, so why not signal so to recover?
>
> See http://golang.org/ref/spec#Handling_panics
>
> """"
> The return value of recover is nil if any of the following conditions holds:
>
> panic's argument was nil;
> the goroutine is not panicking;
> recover was not called directly by a deferred function.
> """"
>
> IOW, the behavior of panic(nil) vs recover() result is strictly
> specified - and thus expected. Also mind the Go 1 compatibility
> promise.
>

I agree that that’s what the spec says, and that changing so would break Go 1, I was intending to ask about the purpose of the behavior

> BTW: The specified behavior of panic(nil) is _very_ useful. One can
> also think about it as: recover simply returns what the argument to a
> possible panic was, no special cases.

I guess that’s nice, but it still seems like one would rather signal the panic. For example, in the example code in that section of the spec, if one wanted to be more careful, one might say

"
if x := recover(); x != nil{
log.Printf(“run time panic with a non-nil argument: %v,”, x)
}


Are there cases in an honest program where calling panic(nil) (so that the error “hides” from recover) is desirable?

Brendan Tracey

unread,
Jan 22, 2014, 4:37:30 PM1/22/14
to Jan Mercl, golang-nuts
For others curious, I just found this discussion:

which implies that it’s a harder to fix problem than it seems.

Dan Kortschak

unread,
Jan 22, 2014, 4:43:01 PM1/22/14
to Brendan Tracey, Jan Mercl, golang-nuts
The question really is "How would you signal that the difference between a nil nil and a meaningful nil?" This would presumably require an additional type, just as error is used. And then to get behaviour similar to what we see now, the nil would be wrapped sometime between the panic and the recover. This is too magical and doesn't allow the use of nil as a fast path return where it can now - at least one person uses this.

xingtao zhao

unread,
Jan 22, 2014, 6:10:17 PM1/22/14
to golan...@googlegroups.com, Brendan Tracey, Jan Mercl
How about returning a typed nil to panic in this case? For example:
type MyError string

...
panic((*MyError)nil)
...

Ian Lance Taylor

unread,
Jan 22, 2014, 6:43:19 PM1/22/14
to Brendan Tracey, Jan Mercl, golang-nuts
On Wed, Jan 22, 2014 at 1:31 PM, Brendan Tracey
<tracey....@gmail.com> wrote:
>
> On Jan 22, 2014, at 12:13 PM, Jan Mercl <0xj...@gmail.com> wrote:
>
>> IOW, the behavior of panic(nil) vs recover() result is strictly
>> specified - and thus expected. Also mind the Go 1 compatibility
>> promise.
>>
>
> I agree that that’s what the spec says, and that changing so would break Go 1, I was intending to ask about the purpose of the behavior

It's simple. Anything else would be more complex, and therefore
harder to implement correctly and harder to understand in practice.

It would give us another class of problems similar to
http://golang.org/doc/faq#nil_error . That one is bad enough.

Ian

Brendan Tracey

unread,
Jan 22, 2014, 6:49:30 PM1/22/14
to Ian Lance Taylor, Jan Mercl, golang-nuts

On Jan 22, 2014, at 3:43 PM, Ian Lance Taylor <ia...@golang.org> wrote:

> On Wed, Jan 22, 2014 at 1:31 PM, Brendan Tracey
> <tracey....@gmail.com> wrote:
>>
>> On Jan 22, 2014, at 12:13 PM, Jan Mercl <0xj...@gmail.com> wrote:
>>
>>> IOW, the behavior of panic(nil) vs recover() result is strictly
>>> specified - and thus expected. Also mind the Go 1 compatibility
>>> promise.
>>>
>>
>> I agree that that’s what the spec says, and that changing so would break Go 1, I was intending to ask about the purpose of the behavior
>
> It's simple. Anything else would be more complex, and therefore
> harder to implement correctly and harder to understand in practice.

Okay. Thanks everybody.

JT Olds

unread,
Mar 27, 2014, 10:35:52 PM3/27/14
to golan...@googlegroups.com, Ian Lance Taylor, Jan Mercl
Just out of curiousity, how come recover() doesn't return an optional second "ok" style value, like reading from a closed channel does, or typecasts, or cgo functions with errno, or index operations? Many parts of the go language have this optional second value about whether or not the operation actually succeeded.

I can imagine keeping the go1 promise just fine if a recover() callsite expecting a single return value kept the same behavior, and if the callsite had two return values expected, the second is a bool about whether or not a panic was actually ongoing?

If the issue with that solution is that having variadic return value amounts for recover makes the recover function somewhat special and thus complicates the compiler, I can see that argument, but recover is already pretty special as-is.

-JT

Ian Lance Taylor

unread,
Mar 28, 2014, 12:46:51 AM3/28/14
to JT Olds, golang-nuts, Jan Mercl
On Thu, Mar 27, 2014 at 7:35 PM, JT Olds <jto...@gmail.com> wrote:
>
> Just out of curiousity, how come recover() doesn't return an optional second
> "ok" style value, like reading from a closed channel does, or typecasts, or
> cgo functions with errno, or index operations?

Because it would only be required to detect the difference between
panic(nil) and no panic at all. It's not worth it. For programs
where it matters, it's easy enough to avoid doing panic(nil).

Ian

Dave Cheney

unread,
Mar 28, 2014, 2:00:58 AM3/28/14
to golan...@googlegroups.com, Ian Lance Taylor, Jan Mercl
panic/recover a deliberately hard to use, this is by design to discourage their use.

JT Olds

unread,
Mar 28, 2014, 2:09:54 AM3/28/14
to golan...@googlegroups.com, Ian Lance Taylor, Jan Mercl
panic/recover aren't hard to use, they're very easy to use already.

the trouble is it's hard to use recover correctly. things should be easy to use correctly, even if they are hard to use in general.
Reply all
Reply to author
Forward
0 new messages