Which reference is undefined here?

Hi,

I’m still quite new to Julia and am trying to make a simple plot. Please consider the following:

zth=Vector{Vector{Float64}}(undef,length(DaT))
tth=Vector{Vector{Float64}}(undef,length(DaT))
...
zthcnvplot=plot(title="Position",titlefontsize=10,
        xlabel="t",ylabel="z",legend=:topleft,grid=false)
for (i,D) in enumerate(DaT)
    zthcnvplot=plot!(tth[i],zth[i],label="Dimp="*string(D/1000)*" km")
end
display((zthcnvplot))

zth and tth are vectors of vectors, which have correctly been calculated in the part indicated with …, and the lengths match and are preset correctly. Nonetheless, I get an error

UndefRefError: access to undefined reference
Stacktrace:
 [1] getindex(A::Vector{Vector{Float64}}, i1::Int64)
   @ Base ./array.jl:801
 [2] top-level scope
   @ ./In[79]:31
 [3] eval
   @ ./boot.jl:360 [inlined]
 [4] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String)
   @ Base ./loading.jl:1094

Line 31 is the line in the for loop. What is wrong here, which reference is missing? All variables I use have been defined somewhere before.

Have you filled both arrays completely? I.e., are any indices still undef from your initialization?

1 Like

Good point - turns out: no. So, thanks for that.

This of course raises (again) the question to the developers why error messages in Julia are usually rather useless. A much more useful error message would have been “Trying to plot undefined array values in array tth”. An “undefined reference” can really be anything, and the least an error message should do is to tell which of usually several variables in a line causes the trouble. This is never done in Julia, and it needs to be fixed.

I don’t know, it looks like the error message was enough for someone on here to figure out the problem without seeing your full code or an MWE?

Also it looks like you’re working in a Jupyter notebook and the stacktrace says

In[79]:31

Is the error not on line 31?

2 Likes

I think this was a pretty clear cut case, it tells you that the undefined value was in one of the getindex operations on that line, so it’s narrowed down to two variables. It doesn’t say trying to plot undefined values because the error happens before the plotting stage, while dereferencing the arguments. If you get an error like this, you can split it up into

for i in indices
    x = X[i]
    y = Y[i]
    plot(x, y; st=:scatter)
end

if you need more detail. And I’m guessing you would get more helpful messages if you avoided indexing in the first place:

for (t, z, D) in zip(tth, zth, DData)

or even better, simply plot the vectors against each other.

1 Like

Maybe Sukera figured it out because they made the same mistake before and certainly has more experience than I.
Anyway, yes, I am working in a Jupyter notebook, and the error is in indeed in line 31. However, there are several variables in that line, and the error doesn’t tell which one causes the problem. I see no reason why it doesn’t. For instance, if I compile Fortran code with gfortran and there is an error, I usually get that information, and it speeds up debugging a lot.

Maybe I should clarify how I figured this out in the first place. The information you provided (it’s the line with plot!) together with the stacktrace is plenty.

  • The stacktrace itself doesn’t contain plot!, so it has to happen before plot! is called.
  • The top frame of the stacktrace contains getindex(A::Vector{Vector{Float64}}, i1::Int64), so it errored trying to access some index of an array.
  • The only indexing expressions in the line with plot! are tth and zth, both of which you showed to be initialized with undef earlier.

Based on that, the logical conclusion is that trying to access either of the two errored (since zth and tth itself exist), which led me to ask “are you sure you initialized them properly”.


I don’t know how Fortran would tell you during runtime which variable contained the error (unless that was somehow baked into each function call or Fortran would know beforehand that it will error), so I’m kind of confused why/how you expect julia to magically know this. Julia only tracks source code line numbers in the compiled code, not columns or individual expressions. Do you have an example from Fortran, so we could maybe improve the error messages?

6 Likes

I just tried your last suggestion and get the same “access to undefined reference”. Moreover, there is only one line in that loop, and there it says that stuff is plotted; it doesn’t say anything about getindex or whatever else happens under the hood, and that is really one of the problems I as a beginner have: >90% of an error message stacktrace lists some stuff that happens under the hood, often in some library I have never heard of and will never look into, and I have to pick out the little nugget of information that I can actually relate to something I see in my code.

I hope my comments are not taken as bad-mouthing Julia, because that’s not my intention. Quite to the contrary, I try to raise attention to a problem I have had for many months which I think makes getting acquainted with Julia unnecessarily difficult for beginners and people who just want to get stuff done.

Sorry for taking so long to reply, and thank you for your explanation.
I guess your second last sentence gets to the point where I have different expectations of what a compiler/interpreter or a running program should report as an error.
I have tried to cook up a small example of a bug that “works” in both Fortran 90 and Julia, and although it’s less than I had hoped (time is limited), the following might serve to demonstrate at least one issue.
The following short program with a bug is quite silly and useless but I hope it shows what I mean. If you compile this Fortran version:

program bd
implicit none
integer, parameter :: n=20
integer :: i,j=100
real, dimension(n) :: x,y
real :: dx=0.1
do i=1,n
   x(i)=i*dx
   y(j)=3*x(j)
end do
end program bd

with gfortran (v.11.0 in my case) using the flag -fbounds-check, you get this error:

At line 9 of file bugdemo.f90
Fortran runtime error: Index '100' of dimension 1 of array 'y' above upper bound of 20

Error termination. Backtrace:
#0  0x102857577
...

i.e., you are told which of the two arrays and which dimension of it has the problem. If you do something (almost) similar in Julia:

n=20
x=Array{Float64}(undef,n)
y=Array{Float64}(undef,5*n)
dx=0.1
j=100
for i in range(1,n,step=1)
    x[i]=i*dx
    y[j]=3*x[j]
end

the error message is much more verbose but less clear (to me at least) and doesn’t say which of the two arrays in the flawed line is the culprit:

BoundsError: attempt to access 20-element Vector{Float64} at index [100]

Stacktrace:
 [1] getindex(A::Vector{Float64}, i1::Int64)
   @ Base ./array.jl:801
 [2] top-level scope
   @ ./In[6]:8
 [3] eval
   @ ./boot.jl:360 [inlined]
 [4] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String)
   @ Base ./loading.jl:1094

This is in spite of having given y the length 100 in the Julia version to make the source of the error unambiguous; if I hadn’t done that, the error message would still be the same.
Of course, here debugging is not such a bit challenge, but you can easily imagine more crowded expressions where it becomes a pain to sort out this type of problem.
I don’t know if it is possible to enable Julia to provide this additional information without sacrificing performance. I should think that it must be feasible, because after all it must know which array has exceeded its bounds. Or is there already a means to do that?
At any rate, I hope this illustrates my point.

I’m not sure there is a way to give you the “name” of the array: getindex is a regular function which sees the value of its arguments, not their “names”

1 Like

It’s a value, there is a name referring to the value in the parent frame at the call site in the appropriate argument position, I don’t see why it’s not possible to connect the two…at least in theory.

Is that this issue @tim.holy ? Julep: Expr provenance when lowering · Issue #31162 · JuliaLang/julia · GitHub

In general having error messages expressed in terms of user code is best.

1 Like