Error when using @load after if statement

Hi there – I would like to write a code that loads all data of a file, but only in case this file exists. I use the @load function of JLD2. However, integrating @load into an if statement leads to an error if the file does not exist. Does anyone have a suggestion to get around this? Here is a code example:

using JLD2

if isfile("TEST_FILE.jld2")
    @load("TEST_FILE.jld2")
end

The error does not appear if jldopen is used, but @load works much better for my needs. Whatever the reason is, I am interested to load all data from a file, if the file exists (Breakpointfile from a long-running code).
Many thanks! Jonas

Hi Jonas,

The problem with @load is that the opening of the file does not occur in the returned Expression, but in the body of the macro itself. Therefore, the file will be opened at parse-time, regardless of the if-statement.

@load implementation
julia> @less @load("TEST_FILE.jld2")

macro load(filename, vars...)
    if isempty(vars)
        if isa(filename, Expr)
            throw(ArgumentError("filename argument must be a string literal unless variable names are specified"))
        end
        # Load all variables in the top level of the file
        vars = Symbol[]
        f = jldopen(filename)
        try
            for n in keys(f)
                if !isgroup(f, lookup_offset(f.root_group, n))
                    push!(vars, Symbol(n))
                end
            end
        finally
            close(f)
        end
    end
    return quote
        ($([esc(x) for x in vars]...),) = jldopen($(esc(filename))) do f
            ($([:(read(f, $(string(x)))) for x in vars]...),)
        end
        $(Symbol[v for v in vars]) # convert to Array
    end
end

Before continuing, let me first point out that @load and @save are listed under Legacy in the documentation, and they mention that “Over time a range of issues have been opened by new users struggling with them.” In other words, it’s probably best to refactor your code to avoid @load.

That being said, you could easily ‘fix’ @load by adding your isfile(filename) check before the f = jldopen(filename) line, e.g. as isfile(filename) || return. (Note that you’ll have to import JLD2.lookup_offset, JLD2.isgroup.) Alternatively, you can move the jldopen to inside the quote. Or if you want a quick-and-dirty hack, you can delay the macro parsing, e.g. via

julia> if isfile("non_existing_file.jld2")
           eval(:(@load("non_existing_file.jld2")))
       end

julia> if isfile("existing_file.jld2")
          eval(:(@load("existing_file.jld2")))
       end
2-element Vector{Symbol}:
 :hello
 :xs

Dear eldee
Many thanks for the detailed explanation! It fixed the error and furthermore I learned a lot.
Best wishes

1 Like