I’m not sure this is true, but I think at this point we actually need to the input of someone who knows Julia’s implementation better than either of us. I was under the impression the interpreter does play a role in runtime eval, but I guess we need more information about this topic.
I do remember there was a point in the past when you couldn’t use global variables in loops at the top level in the REPL and they changed some things to make this possible because people found it pretty weird.
Traces of this can still be found when trying to do the same thing in a script, which isn’t something that should be to common in real code:
#!/usr/bin/env julia
x = 0
for i in 1:10
x += 1
end
println(x)
.
$ ./loop.jl
┌ Warning: Assignment to `x` in soft scope is ambiguous because a global variable by the same name exists: `x` will be treated as a new local. Disambiguate by using `local x` to suppress this warning or `global x` to assign to the existing global variable.
└ @ ~/loop.jl:6
ERROR: LoadError: UndefVarError: `x` not defined
Stacktrace:
[1] top-level scope
@ ~/loop.jl:6
in expression starting at /home/ninjaaron/loop.jl:5
vs in the REPL
julia> x = 0
0
julia> for _ in 1:10
x += 1
end
julia> println(x)
10
However, I think this is not solely related to the use of the interpreter, since the interpreter is invoked every time Julia runs, not only in REPL mode.
Runtime eval and adding new methods is not implemented via Julia’s interpreter. It’s implemented via LLVMs JIT which allows mutation of the method table.
This is not really accurate, at least if I understand your meaning correctly. The last time I heard, which was around Julia 1.4 days, the method table and method resolution was managed in a C runtime library (this could be considered part of the interpreter, in fact). Once the right method is found, it either sends it off to LLVM for code-gen or used cached machine code. LLVM itself has nothing to do with binding methods to functions or method resolution, last I heard, which was a while ago.
I actually remember looking at the code for method resolution back then during a talk at JuliaCon which was based on a thesis demonstrating Julia was “soundly typed”.
So a super simple 800 LOC interpreter is the easiest way to implement this, but is not strictly necessary for Julia’s interactive workflow, turning it into an implementation detail.
I would not restrict the interpreter to only what is found in interpreter.c, but also include toplevel.c and the other runtime C libraries it depends upon. julia is a (mostly) C program which executes Julia programs—mainly by generating machine code with LLVM—but there’s still quite a lot going on in the Julia runtime.