Skip to content

spec: clarify defer semantics #8107

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

Closed
griesemer opened this issue May 27, 2014 · 10 comments
Closed

spec: clarify defer semantics #8107

griesemer opened this issue May 27, 2014 · 10 comments
Labels
Documentation Issues describing a change to documentation. FrozenDueToAge
Milestone

Comments

@griesemer
Copy link
Contributor

Clarify that defer of nil functions panics when the function is deferred, not when the
deferred function is executed.

The spec says that:

"Each time the "defer" statement executes, the function value and
parameters to the call are evaluated as usual..."

( http://tip.golang.org/ref/spec#Defer_statements ). The section on function calls says:

"Calling a nil function value causes a run-time panic."

( http://tip.golang.org/ref/spec#Calls ).

From this we cannot conclude that deferred nil functions must panic upon deferral.
@dvyukov
Copy link
Member

dvyukov commented May 27, 2014

Comment 1:

This is raised after weird GoSmith programs, right?

Labels changed: added gosmith.

@griesemer
Copy link
Contributor Author

Comment 2:

Possibly. I just made myself a note because r asked about it.

@griesemer
Copy link
Contributor Author

Comment 3:

The spec is unclear; which way to go requires some thinking. Possible solutions:
1) Fail upon encountering go/defer function.
2) Fail upon activating go/deferred function.
3) Leave to implementation (spec does not specify).

@griesemer
Copy link
Contributor Author

Comment 4:

Issue #8109 has been merged into this issue.

@gopherbot
Copy link
Contributor

Comment 5 by alan@alandonovan.net:

I think we should specify the behaviour one way or another, but my reading of the
current spec is that it already does require a specific behaviour: #2, fail upon
activation.  
I don't see any major benefit to specifying behaviour #1 instead, since any programming
errors will eventually be detected and reported with certainty during the same execution.

@griesemer
Copy link
Contributor Author

Comment 6:

The main drawback of 2) is that deferred functions may be activated during a panic, and
if the function is nil, this will result in yet another panic. It seems much better to
get that 2nd panic first.

@gopherbot
Copy link
Contributor

Comment 7:

CL https://golang.org/cl/145960043 mentions this issue.

@ianlancetaylor
Copy link
Contributor

Comment 8:

Using defer or go with a nil function is sure to be a programming error.  I think it's
entirely reasonable to panic when the statement is executed rather than when the
function is executed.
But see also issue #8045.

@rsc
Copy link
Contributor

rsc commented Sep 19, 2014

Comment 9:

The defer statement evalutes fn and args "now" and then executes an actual fn(args) call
"later". There is no problem with having a nil fn in Go until you call it. Since the
call happens "later", the panic does not happen until "later". I think this is all
implied by the current spec but I think it is also fine to say explicitly.
I think calling a nil func is roughly analogous to deferring an execution that
dereferences a nil argument:
    func printptrvalue(y *int) { println(*y) }
    var x *int
    defer printptrvalue(x)
x is not dereferenced until "later". There is no reason the panic should happen "now".
Even if the compiler can see that it will panic at execution, the semantics are that the
execution happens "later", not "now".
My reading of the CL is that it reiterates that the panic for deferring a nil func call
happens "later". I agree with that.
I have also checked that all versions of Go I can run on my laptop match this behavior
(really, they'd have to go out of their way not to):
g% cat /tmp/x.go
package main
import "os"
func main() {
    var f func()
    defer f()
    os.Exit(0)
}
g% go1.1 run /tmp/x.go
g% go1.2 run /tmp/x.go
g% go1.3 run /tmp/x.go
g% go run /tmp/x.go
g% 
This issue was filed as collateral damage from issue #8047, which was that the stack
copier didn't work correctly with deferred nil functions. That bug was introduced and
fixed during the 1.3 cycle, so deferred nils have worked in all released copies of Go.

@griesemer
Copy link
Contributor Author

Comment 10:

This issue was closed by revision b4eb22d.

Status changed to Fixed.

@griesemer griesemer added fixed Documentation Issues describing a change to documentation. labels Sep 19, 2014
@griesemer griesemer self-assigned this Sep 19, 2014
@rsc rsc added this to the Go1.4 milestone Apr 14, 2015
@rsc rsc removed the release-go1.4 label Apr 14, 2015
@golang golang locked and limited conversation to collaborators Jun 25, 2016
wheatman pushed a commit to wheatman/go-akaros that referenced this issue Jun 25, 2018
Fixes golang#8107.

LGTM=iant, rsc, r
R=r, rsc, iant, ken
CC=golang-codereviews
https://golang.org/cl/145960043
wheatman pushed a commit to wheatman/go-akaros that referenced this issue Jul 9, 2018
Fixes golang#8107.

LGTM=iant, rsc, r
R=r, rsc, iant, ken
CC=golang-codereviews
https://golang.org/cl/145960043
wheatman pushed a commit to wheatman/go-akaros that referenced this issue Jul 30, 2018
Fixes golang#8107.

LGTM=iant, rsc, r
R=r, rsc, iant, ken
CC=golang-codereviews
https://golang.org/cl/145960043
This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Documentation Issues describing a change to documentation. FrozenDueToAge
Projects
None yet
Development

No branches or pull requests

5 participants