A lot of questions get asked here about interpreted vs compiled language implements. I'm wondering whether the distinction actually makes any sense. (Actually the questions are usually about languages, but they are really thinking about the most popular implementations of those languages).

Today almost no implementation is strictly interpreted. i.e. pretty much nobody parses and runs the code one line at a time. Additionally, implementation which compile to machine code are also becoming less common. Increasingly, compilers target some sort of virtual machine.

In fact, most implementation are converging on the same basic strategy. The compiler produces bytecode which is interpreted or compiled to native code via a JIT. Its a really of mix of the traditional ideas of compilation and interpretation.

Thus I ask: Is there a useful distinction between interpreted implementations and compiled implementation these days?

Your basic assumptions are invalid. The VM model is new and there are some popular languages in that realm, but it's never going to replace the existing models, and there's no convergence on it at all.
–
DeadMGFeb 26 '12 at 19:01

@DeadMG Given that the majority of new languages introduced in the last 10 years or so primarily run on some kind of VM, I'd say he has a point. Of course there still are (and will be for decades to come) languages compiled to native code, and a JIT will remain luxury (or not, if the PyPy guys have their way). So yes, possible overstatement, but I agree that the mainstream (for now and the forseeable future) seems to be bytecode compiler + possibly JIT.
–
delnanFeb 26 '12 at 19:08

3

@DeadMG, you must have a long white beard, if the VM model is "new" for you. P-code had been introduced in 1966 first. IBM Aix is around since 1986.
–
SK-logicFeb 27 '12 at 8:33

4

Things like unix shells, Tcl and alike would always be purely interpreted, so the distinction makes sense, at least in an academic CS. But it is true that when coders are mumbling about interpreters vs. compilers they're not making any sense in most of the cases.
–
SK-logicFeb 27 '12 at 8:35

5 Answers
5

It's important to remember that interpreting and compiling are not just alternatives to each other. In the end, any program that you write (including one compiled to machine code) gets interpreted. Interpreting code simply means taking a set of instructions and returning an answer.

Compiling, on the other hand, means converting a program in one language to another language. Usually it is assumed that when compilation takes place, the code is compiled to a "lower-level" language (eg. machine code, some kind of VM bytecode, etc.). This compiled code is still interpreted later on.

In regards to your question of whether there is a useful distinction between interpreted and compiled languages, my personal opinion is that everyone should have a basic understanding of what is happening to the code they write during interpretation. So, if there code is being JIT compiled, or bytecode-cached, etc., the programmer should at least have a basic understanding of what that means.

The distinction is deeply meaningful because compiled languages restrict the semantics in ways that interpreted languages do not necessarily. Some interpretive techniques are very hard (practically impossible) to compile.

Interpreted code can do things like generate code at run time, and give that code visibility into lexical bindings of an existing scope. That's one example. Another is that interpreters can be extended with interpreted code which can control how code is evaluated. This is the basis for ancient Lisp "fexprs": functions that are called with unevaluated arguments and decide what to do with them (having full access to the necessary environment to walk the code and evaluate variables, etc). In compiled languages, you can't really use that technique; you use macros instead: functions that are called at compile time with unevaluated arguments, and translate the code rather than interpreting.

Some language implementations are built around these techniques; their authors reject compiling as being an important goal, and rather embrace this kind of flexibility.

Interpreting will always be useful as a technique for bootstrapping a compiler. For a concrete example, look at CLISP (a popular implementation of Common Lisp). CLISP has a compiler that is written in itself. When you build CLISP, that compiler is being interpreted during the early building steps. It is used to compile itself, and then once it is compiled, compiling is then done using the compiled compiler.

Without an interpreter kernel, you would need to bootstrap with some existing Lisp, like SBCL does.

With interpretation, you can develop a language from absolute scratch, starting with assembly language. Develop the basic I/O and core routines, then write an eval, still machine language. Once you have eval, write in the high level language; the machine code kernel does the evaluating. Use this facility to extend the library with many more routines and write a compiler also. Use the compiler to compile those routines and the compiler itself.

Interpretation: an important stepping stone in the path leading to compilation!

IMO, this is the best answer. I'm working on my own toy language and the last paragraph describes the way I'm developing it. It really makes working on new ideas much easier. Also +1 for mentioning CLISP bootstrap process.
–
sinanJul 11 '12 at 7:07

@Winston Ewert, only if you want to. You can stop on LLVM IR level and do whatever you want with it then - interpret it, JIT-compile it, instrument it any way you like. You can even translate it to Javascript and then pass through an interpreter: github.com/kripken/emscripten/wiki
–
SK-logicFeb 27 '12 at 15:20

The beauty of llvm is this deliberate separation between the front end and back end. And the tools for manipulating the middle before targeting the instruction set. You can merge your entire project into bytecode and then optimize across the whole thing, with other compilers you would need to have a single file source or at least one that includes its way down through the source tree so the compiler acts on one combined source. Also one set of tools under llvm is generic to all targets, you dont have to build for each target, one compiler fits all (at least to the asm of the target).
–
dwelchFeb 28 '12 at 7:22

Actually lots of implementations of languages are still strictly interpreted, you just may not be aware of them. To name a few: the UNIX shell languages, The Windows cmd and PowerScript shells, Perl, awk, sed, MATLAB, Mathematica and so on.

I believe Perl is internally compiled to bytecode, and at least Mathematica can be compiled. And nothing dictates the implementation of awk and sed (I believe some of the GNU coreutils compile regular expressions to finite automata before execution, which would arguably put them into the "compile to intermediate representation, interpret that" category).
–
delnanFeb 26 '12 at 19:12

1

Actually I'm pretty sure that Perl, MATLAB, Mathematica all compile to bytecode. I'm not familiar with PowerScript, do you mean Powershell? If so, that using the CLR and so does use bytecode.
–
Winston EwertFeb 26 '12 at 19:23

@WinstonEwert, sorry I did mean PowerShell. My understanding is that the translation into an intermediate form does not mean that something is not interpreted. Heck, the original Dartmouth BASIC interpreter translated the source into tokens before interpreting. Each of the tools I mentioned has a mode where it 1) reads a line of source, 2) translates that line into an executable form (possibly some intermediate code rather than native code), 3) executes the code for that line, 4) loop back to 1). That corresponds to my understanding of an interpreter.
–
Charles E. GrantFeb 26 '12 at 19:54

2

Bytecode does imply compiled. A bytecode compiler is simply a program that takes the source and converts it to bytecode. Hence all uses of bytecode must involve a bytecode compiler. But bytecode also has to be interpreted (or JITted). So anything using bytecode is an interpreter/compiler hybrid.
–
Winston EwertFeb 27 '12 at 0:59

4

Really, my thing is that people toss out statements like "python is interpreted" and "Java is compiled" with no understanding of the implementations. I'm questing whether its even useful to describe an implementation in those terms. The truth usually more complicated, and trying to boil it down to interpreted/compiled isn't useful.
–
Winston EwertFeb 27 '12 at 1:16

Nonsense. Self-modifying (machine) code is the oldest trick in the book. Then again, some argue even native code is ultimately interpreted by an interpreter cast into silicon (the CPU). But if we assume that, all code is interpreted and there's no distinction to make.
–
delnanFeb 26 '12 at 19:09

2

@delnan is right. I'll just add that modern languages can modify themselves by creating new classes dynamically and loading/unloading libraries (or "assemblies" in .NET for example)
–
JalaynFeb 27 '12 at 7:35

2

Common Lisp is compiled, but you still can replace function definitions in runtime easily.
–
SK-logicFeb 27 '12 at 8:37