DEV Community

Discussion on: Explain Interpreted Programming Languages Like I'm Five

Collapse
 
etcwilde profile image
Evan Wilde

This answer is not for a 5-year-old, but it's something I've been visiting as a mental exercise lately so I want to do a mind-dump. So.. this should probably be rated PG13, so proceed with caution. (It is totally safe for work though, just some weird concepts.)

So I've actually been re-pondering this topic with my supervisor a lot lately. I actually sent an email to Dan Grossman asking what the difference between a compiled and interpreted language. He is strongly of the belief that there is no such thing as an "interpreted language" or "compiled language", only an implementation decision.

So, the basic spoon-fed definition of an interpreted language would be one that has a program that executes the code, doing the translation and interpretation of the language at runtime. Okay, fine. That works for an old version of, say, python. But... even with modern python, it's partially compiled. Java is another example of where things get messy. So, people used to tell me that Java was essentially an interpreted language because, even though it's converted to an intermediate representation that is then run on the JVM. Okay great, sounds like the JVM is an interpreter (which yes, might have a JIT compiler). Great. But wait a second, there are actually a few hardware implementations of the JVM. Okay... now what? So we have a hardware implementation of an interpreter. Technically, all CPUs are hardware-based interpreters of their underlying instructions. So... that means that in order to determine if Java is interpreted or is compiled depends on knowing what hardware it is running on. Sounds like it really isn't the language anymore. More, the implementation of that language.

So, we can't use the old definition of an interpreted language anymore. I have kind of internalized a new definition of an interpreted language. It comes down to the need to re-access the AST (either full or partially) of the higher-level code at runtime. So far, none of the language features that I can think of inherently require accessing the AST again except for one. The eval function. With eval, you can take any input and execute it. Take python eval(input()), it's a bad idea, yes, but this is really the only situation that cannot be pre-compiled since the thing it is compiling will only be supplied at runtime. This is where Dr. Grossman's argument and mine separate. He argues that there is no issue with simply including the compiler in the binary executable, but I feel like that is cheating. With my updated definition, this technique would still list it as an interpreted language though since part of the AST (the part that is being supplied by the user) is being handled at runtime.

If we're going with my new definition, then the only difference between the two is a language that includes an eval function is an interpreted language, as enforced by the language, and languages that don't include this function are free to be implemented with an interpreter or with a compiler. Different language properties definitely lend themselves to be implemented on one or the other more easily, but it doesn't appear to be a requirement of the language.

As a little side note, I've seen C interpreters. It's weird because of our own predisposition to believe that C is a compiled language since it usually is, but no feature of the language itself requires it to be compiled, and I didn't see anything that specifically states that it MUST be compiled either. So, technically, it's still just C.

In summary, there are no such thing as a "compiled language" or an "interpreted language", only the implementation of the language. There is the one caveat to that, if you change your definition of an interpreted language as being a language that must re-evaluate part of the AST, then a language that requires an 'eval' function is strictly an interpreted language.