This has been true for as long as Go has existed too.
This has been true for as long as Go has existed too.
I’ll accept that the definition of “interpreter” is a little more blurred these days now that pretty much all JIT languages compile to byte code. But I’d argue that the byte code is typically closer to machine code than it is source and thus the only languages that are common place and truly still fully interpreted are shell scripts (like Bash).
>>> Go will generally be vastly faster than interpreted languages regardless of versions.
Python is clearly in the latter group.
As for,
> byte code is typically closer to machine code than it is source
I would very much like to see some evidence; last I'd seen, it was basically tokenized source code and that's it, still nowhere near anything resembling binary executable code.
I’ve written more on to your other post https://news.ycombinator.com/item?id=30215323
Its "byte code" is a not that different than the interpreter reading the lines directly.
I posted more about my point below (https://news.ycombinator.com/item?id=30208039) little point repeating myself here too
Python's not JIT, either. It reads bytecode - which AFAIK is just the source code but tokenized - and it runs it, one operation at a time. It doesn't compile anything to native CPU instructions.
CPython’s virtual machine is stack based thus the byte code is more than just tokenised source code.
In fact there’d be very little point just tokenising the source code and interpreting that because you get no performance benefit over that vs running straight off the source. Whereas compiling to a stack machine does allow you to make stronger assertions about the runtime.
One could argue that the byte code in the VM is interpreted but one could also argue that instructions in a Windows PE or Linux ELF are interpreted too. However normal people don’t say that. Normal people define “interpreted” as languages that execute from source. CPython doesn’t do this, it compiles to byte code that is executed on a stack machine.
Hence why I keep saying the term “interpreted” is misused these days.
Or to put it another way, Visual Basic and Java behaved similarly in the 90s. They compiled to P-Code/byte code that would execute inside a virtual machine and at that time the pseudo code (as some called it - not to be confused with human readable pseudo code but technically “pseudo” is what the “P” stands for in “P-code”) was interpreted instruction by instruction inside a stack machine.
Those languages were not classed as “interpreted”.
The only distinction between them and CPython is that they were AOT and CPython is JIT. And now we are back to my point about how you’re conflating “interpretation” with “JIT”.
Talking about conflating though, AOT and JIT mean different things in a programming context...
Ie many languages are still called “interpreted” despite the fact that their compiler more or less functions exactly the same as many “compiled languages” except rather than being invoked by the developer and the byte code shipped, it’s invoked by the user with the source shipped. But the underlying compiler tech is roughly the same (ie the language is compiled and not interpreted).
Thus the reason people call (for example) Python and JavaScript “interpreted” is outdated habit rather than technical accuracy.
Edit:
Let’s phrase this a different way. The context is “what is an interpreted language?”
Python compiles to byte code that runs on a stack machine. That stack machine might be a VM that offers an abstraction between the host and Python but none the less it’s still a new form of code. Much like you could compile C to machine code and you no longer have C. Or Nim to C. Or C to WASM. In every instance you’re compiling from one language to another (using the term “language in a looser sense here”).
Now you could argue that the byte code is an interpreted language, and in the case of CPython that is definitely true. But that doesn’t extend the definition backwards to Python.
The reason I cite that the definition cannot be extended backwards is because we already have precedence of that not happening with languages like Java (at least with regards to its 90s implementation. I understand things have evolved since but not poked at the JVM internals for a while).
So what is the difference between Java and Python to make this weird double standard?
The difference is (or rather was) just that JIT languages like Python used to be fully interpreted and thus lazily still referred to that way. Where as AOT languages like Java were often lumped in the same category as C (I’m not saying their compilation process is equivalent because clearly its not. But colloquially people to often lump them in the same group due to them both being AOT).
Hence why I make comparisons to some AOT languages when demonstrating how JIT compilers are similar. And hence why I make the statement that aside from shell scripting, no popular language is interpreted these days. It’s just too damn slow and compilers are fast so it makes logical sense to compile to byte code (even machine code in some instances) and have that assembled language interpreted instead.
Personally (as someone who writes compilers for fun) I think this distinction is pretty obvious and very important to make. But it seems to have thrown a lot of people.
So to summarise: Python isn’t an interpreted language these days. Though it’s runtime does have an interpretation stage, it’s not interpreting Python source. However this is also true for some languages we don’t colloquially call “interpreted”.
For one, a Python syntax issue in a function that's not called will never emerge even if the source file is read and run.
With Java you wouldn't even get that source to bytecode format to begin with.
If CPython behaved identical to Javas compiler people would moan about start up times.
Some AOT languages can mimic this behaviour too with hot loading code. Though a lot of them might still perform some syntax analysis first given that’s an expectation. (For what it’s worth, some “scripting languages” can do a complete check on the source inc unused functions. Eg there’s an optional flag to do this in Perl 5).
I will concede things are a lot more nuanced than I perhaps have credit for though.
https://en.wikipedia.org/wiki/V8_(JavaScript_engine)
You’d have more luck if you exampled Bash scripting :P
If you want to be pedantic then these days even those languages that were considered “interpreted” have had their interpreters rewritten to produce byte code that is generally closer to machine code than it is the original source. So they’ve grown beyond the original definition of “interpreted” and evolved into something much closer to a compiled languages.
So if think it’s disingenuous to still call them “interpreted”. And in the case of JavaScript (your example), the largest runtime in use is most definitely a compiler considering it spits out machine code. So that’s definitely not interpreted like you’ve claimed.
In the link I posted:
> V8 first generates an abstract syntax tree with its own parser.[12] Then, Ignition generates bytecode from this syntax tree using the internal V8 bytecode format.[13] TurboFan compiles this bytecode into machine code. In other words, V8 compiles ECMAScript directly to native machine code using just-in-time compilation before executing it.[14] The compiled code is additionally optimized (and re-optimized) dynamically at runtime, based on heuristics of the code's execution profile. Optimization techniques used include inlining, elision of expensive runtime properties, and inline caching. The garbage collector is a generational incremental collector.[15]
Emphasis mine.
So no, it is not an interpreter. It is definitely a compiler.
It seems people today are confusing “interpreter” with “just in time”…
> With Ignition, V8 compiles JavaScript functions to a concise bytecode, which is between 50% to 25% the size of the equivalent baseline machine code. This bytecode is then executed by a high-performance interpreter which yields execution speeds on real-world websites close to those of code generated by V8’s existing baseline compiler.
Emphasis mine.
https://v8.dev/blog/ignition-interpreter
You can also find this information on the Wikipedia article you linked to
> In 2016, the Ignition interpreter was added to V8 with the design goal of reducing the memory usage on small memory Android phones in comparison with TurboFan and Crankshaft. Ignition is a Register based machine and shares a similar (albeit not the exact same) design to the Templating Interpreter utilized by HotSpot.
> In 2017, V8 shipped a brand-new compiler pipeline, consisting of Ignition (the interpreter) and TurboFan (the optimizing compiler).
Which is the point I’m making. Back in the 80s and 90s scripting languages often had no compilation stage aside maybe building an AST and were pretty much 100% interpreted. Anything that ran from byte code was considered compiled (like BASIC vs Java, VB6). Interpreters often ran line by line too.
These days most scripting languages that were traditionally interpreted languages run more like Java except compiled JIT rather than AOT.
But it seems people have warped “interpreted” to mean JIT to compensate for the advancements in scripting runtimes. That is a bastardisation of the term in my opinion. But when you look through this thread you’ll see the same error repeated over and over.
If you want to get pedantic then that byte code is interpreted but frankly where do you draw the line, are retro console emulators interpreters since they translate instructions from on architecture to another in much the same way? Technically yes but we don’t like to describe them in that way.
This is why I keep saying term “interpreted language” used to mean something quite specific in the 80s and 90s but these days it’s pretty much just slang for “JIT”.