This article is a short guide to debugging with
shinybreakpoint
, i.e. what exactly happens after the
breakpoint is set and session is refreshed. If one would like to read
more systematically about debugging in {Shiny}
, it should
be relatively easy to find many useful articles.
Reference to the file
When the file is source()
d or parse()
d,
srcref
attribute is added to the functions to indicate
where the objects originated1. This attribute contains the code (for
chosen object) as shown in the file, e.g. with the comments, and also
path to the file. Knowing this, it is possible to show to the user
location (in the file, not just in the body of function) where the
computation stops.
Unfortunately, after the body of function is modified, this attribute
is lost. We could now distinguish between the srcref
attribute for function itself and for the body()
of that
function and say that attr(fun, "srcref")
is lost, but not
attr(body(fun), "srcref")
, but it won’t help us very much -
we still won’t be able to point to the original file when debug mode
starts. Some solutions are of course possible to show the ‘stop’
location in the file - RStudio displays the original file (where
browser()
is not visible), but shinybreakpoint
constructs temporary file (in temporary location which exists as long as
R session - do not confuse with Shiny session) where the whole added
code is visible, separated by two lines of comments - first one
indicates where the additional code starts and the second one reminds
that this is only temporary file. Temporary file is constructed for each
breakpoint. Having the separate file has downsides, of course, but on
the other hand it allows to modify the (temporary) file without any fear
which could accompany the user when working with original file. Debug
mode is not just a mode to read a values, but the possibility to execute
any code is a very convenient way to experiment with different
solutions.
Stepping through the code
One way to execute code in the debug mode is just to type this code
in the console or move the cursor from one place to another in the file
(to copy the line or execute it directly from the editor by Ctrl + Enter
shortcut). Another way is to use the shortcuts available in the debug
mode (see ?browser
) - like n
to go to the next
line or use panel in RStudio with buttons dedicated to debug mode.
In the context of shinybreakpoint
two things should be
highlighted. First one is that to exit from debug mode without stopping
the app, c
or f
should be used -
c
is preferred, because when f
is used,
RStudio still displays the debug mode panels even that we are no longer
in the debug mode and app runs as usual.
The second one is debugging regular functions. Currently
shinybreakpoint
allows to set breakpoint only in the
reactive context, but it doesn’t mean that regular functions can’t be
debugging. To do this, breakpoint should be set in the reactive context
just before the function call and then in the debug mode is an option to
step into function call (s
or dedicated button in the
panel).
Displaying values
Generally, in R value can be displayed in two ways: by using
print(var)
or just by typing var
in the
console (where var
is a variable). Because n
,
s
and other shortcuts available during the debug mode are
valid variable names, it can happen that indeed variables will have
names the same like the shortcuts - in this situation it is needed to
use print()
to display value.
However, it can be also the case when the value won’t be displayed,
no matter which method is used. In case of Shiny applications, it
happens when debugging renderPrint
, because the output is
captured by the web browser. To be able to display the values, it is
necessary to call sink()
in the debug mode and then values
can be displayed. When exiting from the debug mode, session is
refreshed, so there is no negative consequence of using
sink()
.
One-time breapoint
shinybreakpoint
allows to set only one breakpoint - in
case more breakpoints will be set, only the last one will be saved.
Additionally, breakpoint is removed after exit from the debug mode - it
is necessary, because otherwise we could end up in the infinite loop if
breakpoint would be set in reactive context which is run when the app
(session) starts - that’s because session is refreshed when exiting from
debug mode.
There is, however, an example of behavior which could led to the situation when breakpoint seems to be persist. In some web browsers (when breakpoint is hit) app freezes (is in loading state), but this is not always the case - sometimes UI is still available. And then, when some input will change (what will trigger reactive context where breakpoint was set before), user will end up in the debug mode again after closing it. To avoid this, UI shouldn’t be used during debug mode.