notebook: defer is executed at the end of a cell
sbinet opened this issue · 7 comments
hi,
I am converting a few neugram.io-based notebooks to gopherdata+gomacro.
In these neugram notebooks, a defer
would only be executed at the end of the notebook, not at the end of the cell/block. e.g.:
// cell-1
f, err := os.Open(fname)
if err != nil {
panic(err)
}
defer f.Close()
// cell-2
_, err = f.Write([]byte("hello"))
if err != nil {
panic(err)
}
this would work in neugram, but fails with gomacro, as f
has been closed in cell-1.
could this be fixed?
thanks.
There is currently no hook to run code at the end of a notebook, and each cell is executed sequentially and "separately" from the others.
I understand the use case, but it's not easy to implement it.
Also, since in interactive use there may be no "end of notebook" concept, I am a bit worried that top-level defers could become basically a no-op
in neugram, we had to introduce a top-level function, "main", where all the statements and expressions would be accumulated, including the defer
s.
of course, in the notebook mode the defer
s wouldn't be executed (or at least that wouldn't be visible from the web interface), but they would in the "simple" REPL case (when exiting the interpreter.)
I understand this may be problematic to implement with gomacro.
but usually notebooks are used for either tutorials or "public relations", and having code that explicitly comments out defer
statements isn't great :)
If you mean that jupyter notebook distinguishes "run this existing notebook begin to end" from "open a notebook and run it interactively under user's control", that may be a solution - but I honestly don't know whether such a distinction exists: do you ?
I don't think such a distinction exists.
(by simple REPL I meant running neugram from the usual UNIX shell.)
"run this existing notebook begin to end" from "open a notebook and run it interactively under user's control" ... whether such a distinction exists
Correct, it is simply the front end sending all the cells in individually for execution.
@sbinet, would it instead be alright to define a builtin like func nbdefer(func later())
(please excuse my Go, it's been a while) that is called when the kernel is shutdown? Similar to how Display
is given to users.
@SpencerPark: that would require changing all defer f(args)
to nbdefer(func () { f(args) })
in the source code to be evaluated. While feasible, it's surprising and cumbersome.
I thought more about it, and it's possible to implement a configuration flag in gomacro that chooses behaviour of top-level defer
between:
- current behaviour:
defer
calls are evaluated at the end of the cell - new behaviour:
defer
calls are evaluated at the end of the notebook
gophernotes could configure behaviour 2) at startup and, clearly, tell gomacro when a notebook is finished (I have no idea how to detect when a notebook is finished - help is welcome)
Does it seem an acceptable solution?
that would require changing all defer f(args) to nbdefer(func () { f(args) }) in the source code to be evaluated.
Good point, that is a bit tedious, and ugly.
how to detect when a notebook is finished
There is the shutdown_request
message that we currently handle in handleShutdownRequest but would need the value for the interpreter passed in from handleShellMessage. A notebook is never "finished" but the kernel is killed when closing it properly ("Close and halt" button) or when manually shutdown. Otherwise it remains running in the background until the server is shutdown.