94

I am cautious of asking this question because it might appear overly fastidious. I just opened up JavaScript: The Definitive Guide, and it states of the first page of chapter 1

"JavaScript is a high-level, dynamic, untyped interpreted programming language”

So am I to take it that the interpreted part is a requirement in the language specification, or is it misleading to say that the language is an interpreted programming language when respecting the difference between a language and its many implementations?

There are no static compilers for JavaScript apparently - https://stackoverflow.com/questions/1118138/is-there-a-native-machine-code-compiler-for-javascript so maybe it's just a reflection of this.

6
  • There was a jscript.net for a while that was similar to AS3 / the "lost" ES4. It was bytecode-compiled to CIL.
    – Hey
    Commented Mar 6, 2012 at 15:53
  • 15
    V8 explicitly claims not to be an interpreter but a compiler.
    – pimvdb
    Commented Mar 6, 2012 at 15:56
  • @GGG JScript.Net is still alive and...sickly. But still alive. msdn.microsoft.com/en-us/library/72bd815a.aspx
    – Jetti
    Commented Mar 6, 2012 at 16:18
  • 1
    FWIW, the "untyped" bit isn't strictly true either
    – Rob Agar
    Commented Mar 6, 2012 at 16:54
  • Firefox had just released the first browser-based JIT compiler the year that question was answered in FF 3.5 so it probably wasn't widely known about at the time. I believe modern JITs actually do a lot of compiling (or at least prep for compile) on the first pass of a JS document to do things like identify and cache methods that are isolated to a given scope. Commented Jun 3, 2013 at 18:45

4 Answers 4

62

So am I to take it that the interpreted part is a requirement in the language specification, or is it misleading to say that the language is an interpreted programming language when respecting the difference between a language and its many implementations?

EcmaScript language geeks often use the term "ES interpreter" to refer to an implementation of EcmaScript, but the spec does not use that term. The language overview in particular describes the language in interpreter-agnostic terms:

ECMAScript is object-based: basic language and host facilities are provided by objects, and an ECMAScript program is a cluster of communicating objects.

So EcmaScript assumes a "host environment" which is defined as a provider of object definitions including all those that allow I/O or any other links to the outside world, but does not require an interpreter.

The semantics of statements and expressions in the language are defined in terms of completion specification which are trivially implemented in an interpreter, but the specification does not require that.

8.9 The Completion Specification Type

The Completion type is used to explain the behaviour of statements (break, continue, return and throw) that perform nonlocal transfers of control. Values of the Completion type are triples of the form (type, value, target), where type is one of normal, break, continue, return, or throw, value is any ECMAScript language value or empty, and target is any ECMAScript identifier or empty.

The term “abrupt completion” refers to any completion with a type other than normal.

The non-local transfers of control can be converted to arrays of instructions with jumps allowing for native or byte-code compilation.

"EcmaScript Engine" might be a better way to express the same idea.


There are no static compilers for JavaScript apparently

This is not true. The V8 "interpreter" compiles to native code internally, Rhino optionally compiles to Java bytecode internally, and various Mozilla interpreters ({Trace,Spider,Jager}Monkey) use a JIT compiler.

V8:

V8 increases performance by compiling JavaScript to native machine code before executing it, versus executing bytecode or interpreting it.

Rhino:

public final void setOptimizationLevel(int optimizationLevel)

Set the current optimization level. The optimization level is expected to be an integer between -1 and 9. Any negative values will be interpreted as -1, and any values greater than 9 will be interpreted as 9. An optimization level of -1 indicates that interpretive mode will always be used. Levels 0 through 9 indicate that class files may be generated. Higher optimization levels trade off compile time performance for runtime performance. The optimizer level can't be set greater than -1 if the optimizer package doesn't exist at run time.

TraceMonkey:

TraceMonkey adds native‐code compilation to Mozilla’s JavaScript® engine (known as “SpiderMonkey”). It is based on a technique developed at UC Irvine called “trace trees”, and building on code and ideas shared with the Tamarin Tracing project. The net result is a massive speed increase both in the browser chrome and Web‐page content.

11
  • 1
    Thanks for this answer, it actually answers the question. I suppose the final comment about no static compilation is what caused the buzz about which implementations actually compile code and which ones do not. All I was interested in was the validity of the statement "JavaScript is an interpreted language" which, given implementation citations and the lack of definition by the spec, appears to be false. Not encouraging for the second paragraph of a "Definitive Guide", but I guess I will stick with it.
    – Matt Esch
    Commented Mar 6, 2012 at 18:30
  • @me232, the statement was substantially true prior to 2008. Rhino pre-dates that but was not a major interpreter and so few would have faulted "the Definitive Guide" at the time for ignoring it. I haven't read the book, so I can't comment on how representative that sentence is of its overall quality. Commented Mar 6, 2012 at 20:58
  • What's the definition of "static compiler". I thought that definition meant compilation happens only once and you get a static (ie, unchanging) bucket of bits that you then execute. AFAIK this is not how any JavaScript engine works. That's why they have de-optimization steps. In other words JavaScript is compiled by these engines but it is not statically compiled.
    – gman
    Commented Mar 29, 2017 at 23:46
  • @gman, Rhino's bytecode generator works that way. Commented Mar 30, 2017 at 0:04
  • AFAIK that's not the case. Rhino can include other JavaScript files which have to be compiled at runtime. That's not static complication.
    – gman
    Commented Mar 30, 2017 at 0:54
30

The emergence of JIT compilers for script languages has blurred the line between compilation and interpretation to a point where the question doesn't mean all that much. Is it only interpretation when the engine reads a line of code and immediately executes it? (Shell scripts are still typically implemented this way.) Is it interpretation when the engine takes the whole file, immediately compiles it to some byte code, and then interprets the byte code? (The first-stage Mozilla engine works this way, as does CPython.) Is it interpretation when the engine parses a function at a time and JIT-compiles it to native code? What about those engines that compile the entire file to byte code, then JIT one function at a time as needed? (Most script engines these days work this way, and the main Java VM works this way too except that compiling to byte code happens ahead of time.)

There are many shades between compilation and interpretation.

I think the most useful definition for interpretation is "is fed the source code of the program at execution time, without a separate ahead-of-time step". By this definition, all the JavaScript engines are interpreters. But this is certainly not the only possible definition of interpretation.

But is JavaScript designed for interpretation? In a way, yes: it has an eval function as well as the Function constructor that you can give program code as a string which will be executed. The ability to dynamically construct program code at run time requires that the engine is capable of interpreting source code. But this doesn't mean that you can't make everything else ahead-of-time. Even in a compiled language like C++ and C# you can take source code, compile it in memory to new machine code and then execute that. There are even libraries for that: LLVM+Clang in C++ and the Roslyn project in C#.

Also, the delivery mechanism for JavaScript is source code; there is no recognized byte code form of it. C# and Java have their official byte code, and everyone expects C++ to be delivered as machine code. But this is still not an inherent aspect if the language, just a dominant usage scenario. In fact, JavaScript's close relative ActionScript in Flash is in fact delivered as byte code (the Flash compiler precompiles all scripts).

1
24

The V8 JavaScript VM used in Chrome doesn't include an interpreter. Instead it consists of two compilers and compiles the code on the fly. One of the compilers runs quickly but generates inefficient code, the other is an optimizing compiler.

I can understand why some people would consider this "cheating", since V8 takes source code as input every time the code runs and the user has to have V8 installed. But consider a compiler which emits an executable which includes a complete interpreter and bytecode. Then you would have a stand-alone program. It just wouldn't be very efficient.

4
  • Nice answer. But I am wondering why the V8 engine has a two step compilation process? Why not compile the source code directly into machine code? Wouldn't that be faster?
    – darKnight
    Commented Feb 23, 2021 at 20:55
  • 1
    That is exactly what it does. It isn't really a two step process, it's more like two separate processes: One fast and one slow. The first process generates inefficient machine code quickly, while the second process generates optimized machine code for the hottest code paths. Commented Mar 7, 2021 at 16:12
  • I see. Could you share some doc which explains this process in detail?
    – darKnight
    Commented Mar 7, 2021 at 16:37
  • I just found out that what I wrote above has not been true since 2017. It seems that V8 now compiles to bytecode. See blog.logrocket.com/… Commented Mar 7, 2021 at 17:10
8

There is no totally agreed upon definition of 'interpreted' versus 'compiled'. In the classic distinction, compiled languages produce a stand-alone binary executable, while interpreted languages requires a deployed runtime to execute the code. Virtual machines, bytecode and so on blurs the distinction.

But here is a possibly useful definition: An interpreted language is a language where the standard language runtime is able to take source code text as input and execute it. By that definition Perl, Python, Ruby, JavaScript and shell scripts and the like are interpreted (even if they use intermediate steps like bytecode or even native code). Java, C#, C etc. are not. And JavaScript is by definition interpreted, even if the spec does not use the exact word.

2
  • 1
    Hmm, I don't like putting Java and C in the same category. Perhaps a better distinction is languages that are most commonly distributed as (A) source code, (B) intermediate code, or (C) machine code. For example A=javascript, B=Java, C=C. Commented Dec 10, 2015 at 17:39
  • 1
    Calling a language either interpreted or compiled isn't right. For example under that rule, you'd agree that C++ is compiled language right? Then what about Cling, that executes c++ code without compiling it. "and the like are interpreted (even if they use intermediate steps like bytecode or even native code)" Acc to this, java is interpreted too, interpreted by its VM. Commented Sep 25, 2016 at 13:03

Not the answer you're looking for? Browse other questions tagged or ask your own question.