UndefVarError when including a snippet of code

question

#1

Imagine that you have many plotting calls that you’re using to debug the code that you are developing. At some point you want to be able to erase the plotting code quickly, commit the changes on git and reinsert the plotting code before development can continue.

I tried to solve this problem with a simple include as follows:

foo.jl

function foo()
  # do something fancy
  fancyobj = ...

  include("plotting.jl")

  # more fancy operations
  fancyobj = ...

  return fancyobj

plotting.jl

using PyPlot

# plotting code using variables defined in foo
plot(fancyobj)
xlabel(); ylabel()...
title(...)...

So whenever I need to commit my changes, I erase a single line include("plotting.jl"), commit and insert it back. The problem is that I am getting this UndefVarError for fancyobj. I assumed that include is equivalent to just pasting the code in place, is that incorrect? If this is the expected behavior, what is a better solution to the problem?


#2

Are you sure it’s not plot that’s undefined? You’re using inside of a function. I am not sure that works. Just put using at the top scope of your module and it should be good.


#3

@ChrisRackauckas below is a MWE:

foo.jl

function foo()
  a = 2
  include("plotting.jl")
end

foo()

plotting.jl

b = 2*a

$ julia foo.jl

Gives me:

ERROR: LoadError: LoadError: UndefVarError: a not defined
in include_from_node1(::String) at ./loading.jl:488
in foo() at /home/juliohm/Desktop/test/foo.jl:3
in include_from_node1(::String) at ./loading.jl:488
in process_options(::Base.JLOptions) at ./client.jl:262
in _start() at ./client.jl:318
while loading /home/juliohm/Desktop/test/plotting.jl, in expression starting on line 1
while loading /home/juliohm/Desktop/test/foo.jl, in expression starting on line 6


#4

include works in global scope. It’s not possible to make it reference local variables.


#5

Ahh yeah, that’s it.

If you want to do compile time copy/paste, use a macro. Here’s a version which works on v0.5 and v0.6.


#6

Is there any other alternative that is simpler? I am trying to avoid writing a macro for every plotting snippet, or I probably don’t understand your proposal.


#7

Define this macro somewhere in your code:

macro def(name, definition)
    return quote
        macro $(esc(name))()
            esc($(Expr(:quote, definition)))
        end
    end
end

Then you can easily make macros to copy/paste

@def MyPlot begin
  plot(fancyobj)
  xlabel(); ylabel()...
  title(...)...
end

Then to paste it around

# some code 
@MyPlot  # paste here
# some code

Defining a macro for each snippet can’t be worse than making a new file for each one.