<p>Some programming languages are implemented via a source code interpreter instead of a compiler, for example Python, PHP, Ruby and Perl, and these programming languages are very popular.</p>
<p>So, this approach has many pros, but cons of course too.
Which are some pros/cons of interpreters?</p>

<implementation><interpreters>
What are the pros and cons of interpreted programming languages?
CC BY-SA 4.0
2023-06-21T10:35:39.870Z
While I agree with @Adám, I feel this post could be more focused. You could maybe talk about the pros-cons of one specific technique; the question seems very broad as is. That being said, I'm not the one who downvoted, so the actual reason may be different.
FireTheLost
CC BY-SA 4.0
2023-06-26T07:42:35.080Z
Languages are not compiled or interpreted. Their implementations are.
SK-logic
CC BY-SA 4.0
2023-06-26T08:55:27.917Z
@SK-logic many languages have specifications that make compilation either impractical or straight up impossible. Python for example brings heavy limitations if you want to use something like Cython or Numba to compile it.
kouta-kun
CC BY-SA 4.0
2023-06-26T10:53:53.463Z
@kouta-kun - impractical - yes, indeed, if the language is too dynamic, especially using dynamic scoping a lot, then you simply won't get any significant performance gains from compiling it. You still can compile it and get the same performance as interpreter does though. You can compile the said Python, see PyPy for example. There can be other reasons to compile, not just to get a better performance.
SK-logic
CC BY-SA 4.0
2023-06-26T11:13:40.893Z
I'm now wondering if any programming language is truly "impossible" to compile, considering JIT as compilation, since like you said worst case you just have loads of runtime dispatch if dynamic typing is heavily used and strange scoping interactions, both of which can be worked around.
kouta-kun
CC BY-SA 4.0
2023-06-26T11:23:00.527Z
@kouta-kun Futamura projections says no, there is no language that cannot be compiled - at the very least you can always specialise an existing interpreter against a source code and it'll be an (inefficient) compilation, no matter what interpreter it is and how it works.
SK-logic
CC BY-SA 4.0
2023-06-26T12:32:10.880Z
It's true that in principle every language can be both interpreted and compiled, as this is a property of an implementation of the language, not of the language itself. But also, many languages are designed to be interpreted, or designed to be compiled, so it's not meaningless to say "an interpreted language" and people generally understand what this means.
kaya3
CC BY-SA 4.0
2023-06-27T00:21:09.903Z
from the perspective of who? for what use-case? and compared to what?
starball
CC BY-SA 4.0
2023-06-29T02:04:28.220Z
@starball I think it's justifiable to leave both of the first two intentionally vague; that way answers can address the different factors that would go into making the decision, which is the real value of the pros-cons format.
rydwolf
CC BY-SA 4.0
2023-07-03T17:53:06.030Z
What does the word "interpreted" mean in this question? As far as theory and implementations are concerned, a compiler _is_ an interpreter. In fact several implementations (and languages!) are designed so that a compiler and/or interpreter for a single language (ie. with no bytecode nor any other IR) exists both AoT and at runtime (Common Lisp, Clojure, Excelsior Jet, IKVM.NET, C++/CLI, D, JSP, JRuby, Quercus, ...).
Longinus
CC BY-SA 4.0
2023-11-18T00:13:56.543Z
Python doesn't use a source code interpreter. It's compiled into byte code, which is then interpreted.
Barmar
CC BY-SA 4.0
2023-11-18T00:35:59.870Z
I feel like this question has been asked a lot of times before…
Someone
CC BY-SA 4.0
2023-11-18T16:54:14.850Z
This question is based on a massive and common misunderstanding. **Very few modern language implementations use source code interpreters.** What is extremely common is that they are **compiled to an intermediate form**, and then **the intermediate form is interpreted** in some form of VM. That leads to a **completely different set of pros and cons** making the question ambiguous to the point of uselessness.
IMSoP
CC BY-SA 4.0
2023-11-24T12:33:55.453Z
@IMSoP indeed. Python is every bit as much "compiled" as Java or C#. It just also happens to offer a mode whereby individual statements can be compiled and immediately executed, in an environment that persists between such compilations.
Karl Knechtel
<p>An issue I've not seen mentioned yet is that interpreters may be subdivided into multiple categories.  Some receive input from a stream, individually processing commands contained therein.  Some execute exclusively from data structures which must be pre-loaded before program execution starts.  Some are capable of executing directly from a stream, or from objects constructed by the execution of previous commands.  The first and third categories may be useful in cases where it may be necessary to start executing parts of a program before the entire program exists (or in some situations, where no &quot;complete program&quot; will ever exist, because each command will be jettisoned from memory after it executes).</p>
<p>Additionally, some interpreters are designed to process source text that would be created by a human or other entity that is designed to produce program source text to accomplish some <em>particular</em> objective, while others are designed to act upon programs which have been first fed through a &quot;transpiler&quot; that might convert e.g. <code>x=y+z;</code> into a sequence of bytes whose meaning might be described as e.g. &quot;pushIntVariable #4; pushIntVariable #7; Add; pushAddressOfVariable #9; StoreInt&quot;.  An interpreter given a such sequence of bytes could avoid having to spend time on things like symbol-table lookup, and thus run must faster than one which must fully parse everything every time it is encountered.</p>
<p>While some tools that are used to run programs are clearly &quot;compilers&quot;, and others are clearly &quot;interpreters&quot;, there are many that end up sharing characteristics of both.</p>

CC BY-SA 4.0
2023-11-20T17:47:52.383Z
2023-11-20T17:47:52.383Z
supercat
CC BY-SA 4.0
2023-11-20T18:00:30.623Z
Upvoted mostly for the last sentence. Dividing languages / implementations into two camps of "compiled" and "interpreted" stopped being useful decades ago.
IMSoP
<p>The ability to product self-modifying code, such as by producing strings that are then executed as if they are a piece of code of said language, are trivial to do in an interpreted language, but not so much in a compiled language.</p>
<p>There is a reason why Python has <code>exec()</code>, JavaScript has the <code>Function()</code> constructor function, and Lua has <code>loadstring()</code>, but C or C++ has no such equivalent. In a compiled language, the only way would be to force the language standard library to include a compiler for said language, which would bloat the language considerably. But in an interpreted language, the interpreter is already there so such constructs are trivially implemented as 'invoke the interpreter on the contents of this string.'</p>

CC BY-SA 4.0
2023-11-18T22:05:33.560Z
2023-11-18T22:05:33.560Z
CPlus
<h1>PROS</h1>
<ol>
<li>Quicker development. Obviously a good thing. There simpler and have dynamic typing which speeds up developemnt. They also have high-level data structures.</li>
<li>Easier debugging. It is more interactive which allows for this. They can experiment with code snippets without a compile build run cycle thats separate.</li>
<li>Simplicity. There is more straightforward syntax and expressive constructs. This is ovbiously good and makes it more readable as well as easy to learn.</li>
</ol>
<h1>CONS</h1>
<ol>
<li>Worse performance. The code is translated and executed line by line at the runtime and this causes the performance hit. JIT improves it to some extent but not fully.</li>
<li>Development complexity. While its simple to use it is quite hard to make. They might need language runtime or an interpreter.</li>
</ol>

CC BY-SA 4.0
2023-06-26T21:45:37.307Z
2023-06-27T09:40:21.113Z
2023-06-27T09:40:21.113Z
Starship
CC BY-SA 4.0
2023-06-26T22:33:26.853Z
Dynamic typing and late binding are two separate concepts. You can have static typing and late binding (e.g. methods in Java), or dynamic typing and early binding (e.g. local variables in Python).
kaya3
CC BY-SA 4.0
2023-06-26T22:59:29.060Z
It's not clear to me that *any* of these points is fully accurate, if at all. Most of them don't seem to be related to interpretation, and one of the ones that is says "[an interpreted language] might need [...] an interpreter". At the least, the answer could benefit from adding explanation and justification to each of the claims.
Michael Homer
CC BY-SA 4.0
2023-07-02T20:28:16.670Z
All of the pros can be applied to a compiled language, if designed properly. Dynamic typing may even *slow down* development by introducing hard to find type errors
Seggan
<p>In addition to what was said in the other answers:</p>
<p>You'd normally design a language with typically interpreted semantics, as in - some form of a dynamic scoping, dynamic dispatch (probably, duck typing), some form of managed memory, etc., in case if you need a <em>scripting</em> language. An interactive language for a command line interface, for example, or embedded scripting language to control the behaviour of some application.</p>
<p>In such cases interpretation makes sense - firstly, most statements will only be executed once, so no need to waste time compiling them. Secondly, such languages often require very tight interoperability with the functionality of the host system, while code may not be trusted and may require sandboxing. Some believe both are easier to achieve with interpretation.</p>
<p>Having said that, the line between compilation and interpretation is very blurred, all the languages mentioned in the question are in fact bytecode-compiled, and there's quite a few interactive REPLs built on top of natively compiled languages (some Common Lisp implementations, for example).</p>

CC BY-SA 4.0
2023-06-27T09:45:28.187Z
2023-06-27T09:45:28.187Z
SK-logic
CC BY-SA 4.0
2023-06-27T14:21:12.413Z
Very few languages have [dynamic scopes](https://languagedesign.stackexchange.com/q/253/89) ─ typically, any language with a concept of scope will have lexical scopes. Perhaps the distinction you want to draw is between block scope (as in C or Java) and function scope (as in Python or Javascript).
kaya3
CC BY-SA 4.0
2023-06-27T15:16:36.340Z
Both Python and Javascript have dynamic scoping (alongside with rudimentary forms of static scoping). So does elisp, even Common Lisp, Tcl, Perl and many many more.
SK-logic
CC BY-SA 4.0
2023-11-18T00:20:08.090Z
Python variables are lexically scoped by default, you have to use `global` and `nonlocal` to write to dynamically-scoped variables. Similar for Common Lisp; unless you declare a variable `special` it's lexically scoped.
Barmar
CC BY-SA 4.0
2023-11-18T09:19:17.877Z
@Barmar Python scoping rules are weird, there's no nested lexical scoping within a single function definition, all variables share the same scope. I would not call it a proper lexical scoping. You can introduce a variable inside, say, an `if` branch and then use it outside.
SK-logic
CC BY-SA 4.0
2023-11-19T14:35:14.397Z
@SK-logic Just because an if block doesn't introduce a new scope, doesn't make the scopes which do exist "dynamic". In Python, function definitions can be nested, and when they are, it is the *lexically surrounding function* which provides the parent scope, not the *dynamic execution context*. Nor is it particularly "weird" - there are probably as many popular languages using function scope as using block scope.
IMSoP
CC BY-SA 4.0
2023-11-19T17:52:44.293Z
@IMSoP At the very least, I don't think it's as straightforward as "Python has lexical scoping". See the examples given in sections 4.2.2, 4.2.3 and 4.2.4 in [this paper](https://cs.brown.edu/~sk/Publications/Papers/Published/pmmwplck-python-full-monty/paper.pdf). They create a translation of Python into a lexically scoped language and talk about some of the scoping differences.
David Young
CC BY-SA 4.0
2023-11-19T19:40:48.163Z
@DavidYoung OK, but that's interesting, but a) not the same as "dynamic scoping", which is what the answer mentioned; b) not directly related to there being no block-level scope, which is what the comment I was responding to mentioned; and c) entirely unrelated to whether Python has "interpreted semantics" (whatever that means), exactly the same rules could be followed by a compiler - and, in fact, that's what happens, since contrary to the question no popular implementation of Python uses a "source code interpreter".
IMSoP
CC BY-SA 4.0
2023-11-20T11:05:39.403Z
@IMSoP do not forget that global variables in Python are dynamic, and this is one of the major impairments of the language. And this was a design decision made with interpretation assumed as default.
SK-logic
CC BY-SA 4.0
2023-11-20T11:19:09.870Z
@SK-logic I don't know what definition of "dynamic" you're using there, but it's surely not the one normally meant by "dynamic scope", because global variables have *no* scope, by definition. I'm also not sure what the relationship is with interpreter vs compiler implementations - I can't see any barrier to using a global variable in a fully compiled language. But then, I'm not sure what definition of "interpreter" you're thinking of either, since the question incorrectly refers to "source code interpreters", which is definitely not what either CPython or PyPy use.
IMSoP
CC BY-SA 4.0
2023-11-20T12:49:14.860Z
@IMSoP dynamic scoping similar to, say, elisp. If you're designing a language for an interpreter, you'll be ok with looking up a variable in some table every single time it's referenced. If you're designing a language straight away for an efficient compilation, you'll think twice before introducing such semantics. Also, since the OP used the term "source code interpreter" incorrectly, I simply assumed they're talking about any kind of interpreter in general.
SK-logic
CC BY-SA 4.0
2023-11-20T14:52:43.543Z
@SK-logic Unfortunately, I don't know elisp, so that doesn't help; but from what you're saying,  it sounds like you're talking about dynamic *allocation* - i.e. being able to *create* global variables from anywhere? The *scope* of such a variable is still "global", but it's *extent* or *lifetime* is shorter; unlike in, say, C, where a global variable is *statically allocated* and thus has both scope and lifetime of the whole program. It would be possible, but I agree unusual, for a language to compile `global foo;` wherever it occurred into a global static allocation (a kind of "hoisting").
IMSoP
CC BY-SA 4.0
2023-11-20T14:55:19.553Z
@IMSoP no, I am talking about dynamic scoping, which is, in this case, dynamic lookup. Every time the dynamically scoped name is referenced it is looked up again, and can be found in different places every single time. Static scoping means one name in one context always refers to one well defined origin.
SK-logic
CC BY-SA 4.0
2023-11-20T15:02:38.400Z
@SK-logic Then I'm not following at all. In what way can a global variable "be found in different places every single time"? You can't "shadow" one global variable with another global variable; it's global. You can access a variable which hasn't been initialised yet, but that's semantically the same as in any static scope where you don't have to declare variables before the first line of procedural code. It can have different *values*, and those values might be dynamically *typed*, but that's not the same as mapping the name to a different variable.
IMSoP
CC BY-SA 4.0
2023-11-20T19:24:31.063Z
@IMSoP there's a dictionary returned by `globals()`, and Python implementations are expected to respect whatever you'll do with it. This very severely limits the ability of Python compilers to optimise an access to global variables, they must be looked up every single time.
SK-logic
CC BY-SA 4.0
2023-11-20T19:29:20.897Z
@SK-logic That's not "dynamic scoping", though; whenever you access it, the global variable "foo" points to the entry in that dictionary called "foo"; it won't sometimes point to a different entry, or a different dictionary. That entry might be "missing", but that's really just a special value - it will be missing for *everything* that calls it, until it's assigned a new value, then *everything* will see the value.
IMSoP
CC BY-SA 4.0
2023-11-20T21:40:55.697Z
@IMSoP this is exactly how dynamic scoping works in the other dynamically scoped languages. And yes, this entry can point to different origins of the `foo` definition every time you call a function that refers to it. You cannot compile it once and replace with a pointer. You must look it up in the dictionary every single time.
SK-logic
CC BY-SA 4.0
2023-11-20T22:11:50.643Z
@SK-logic I still don't understand what you mean by "different origins of the `foo` definition every time". If there's a single dictionary, then at any moment, it has exactly one entry with a key of `foo`; that's the same as any symbol table, whether it's global, function-local, block-local, etc. Outside of global scope, you have multiple dictionaries (one for each scope), each of which can have its own `foo` *simultaneously*; dynamic scoping means that you choose *between those dictionaries* based on the calling context of the function, *before* looking up the key `foo` in that dictionary.
IMSoP
CC BY-SA 4.0
2023-11-21T20:29:29.017Z
Let us [continue this discussion in chat](https://chat.stackexchange.com/rooms/149825/discussion-between-imsop-and-sk-logic).
IMSoP
<p>I'll try to answer from the perspective of a language implementer/designer and as a user.</p>
<p>I'll also  try to answer as broadly and generally as possible, but <strong>disclaimer</strong>: these lists may not apply to specific languages and implementations. And these lists will not be exhaustive.</p>
<h2>As a User</h2>
<h3>Pros</h3>
<ul>
<li><strong>Better guarantees about behavior.</strong> An interpreter can more easily be written to make user code behave the same no matter what platform it runs on.</li>
<li><strong>An interpreter is more likely to be available on many platforms.</strong> This is not a guarantee, of course, but it's much simpler to port a well-written C, C++, Rust, etc., interpreter than it is to write a backend for yet another platform, especially when many platforms are much the same (you may have x64, but on Linux and Windows) with subtle and not-so-subtle differences.
<ul>
<li><strong>You can probably port the interpreter to a weird platform yourself.</strong> Related to the portability of interpreters, you might be able to port it yourself, as a user, should that be necessary.</li>
</ul>
</li>
<li><strong>Your code can often avoid a compile step.</strong> Another thing that is not a guarantee, but you may be able to skip compilation. This has many great effects:
<ul>
<li><strong>Faster feedback loop for development.</strong></li>
<li><strong>No need to recompile when you update a library.</strong></li>
<li><strong>No need for a complicated build process.</strong> Okay, this one may not be true in some cases, but it does happen.</li>
</ul>
</li>
</ul>
<h3>Cons</h3>
<ul>
<li><strong>Performance sucks.</strong> The rule of thumb is that every layer of interpretation is one order of magnitude slower. This holds surprisingly well across many languages and implementations, so users basically have to assume their code will run 10x slower.
<ul>
<li><strong>More memory consumption.</strong> Related to the above, when you run your program under an interpreter, you need memory for your program <em>and</em> for the interpreter.</li>
<li><strong>Startup time can be prohibitive.</strong> Because this is something that had been a problem for several language implementations (JVM, Python, Julia, among others), I thought I'd better mention it specifically.</li>
</ul>
</li>
<li><strong>The interpreter is a runtime dependency.</strong> You now have to install the interpreter on every machine where the code will run. Have fun.</li>
<li><strong>Existing developer tools don't work.</strong> You have to wait on the implementer or some driven soul to do it. Or do it yourself.</li>
</ul>
<h2>As an Implementer</h2>
<h3>Pros</h3>
<ul>
<li><strong>It's much easier to make the language behave the same on diverse platforms.</strong> No special hacks for weird platforms if your implementation language is good enough or has good enough libraries. (Personal note: I implemented a library of two's-complement arithmetic in portable C that avoids UB. This is some of my secret sauce to make C &quot;good enough.&quot;)
<ul>
<li><strong>It's easier to define all behavior.</strong> Undefined behavior is bad, and it makes users unhappy. With an interpreter, you can more easily define behaviors in your language and eschew the excuse for poor design that undefined behavior is.</li>
</ul>
</li>
<li><strong>It's easier to test.</strong> With an interpreter, you're testing the same code on every platform modulo some small bits. With a compiler, you test a different backend for every platform.</li>
<li><strong>Portability is as easy as you make it.</strong> You can make it easy to port your interpreter to more platforms. <a href="https://youtube.com/watch?v=ThMwHKfzz1I&amp;t=65" rel="noreferrer">It all depends on you,</a> not a finicky platform you don't control.</li>
<li><strong>You don't need some general-ish AST format.</strong> You can use whatever data structures make sense instead of transforming them into SSA, CPS, or some other form of IR that can enable optimization.
<ul>
<li><strong>You don't need to write optimizations for your language or to target a specific IR format.</strong> Related to the above, you can depend on the optimizations of your implementation language and/or avoid the need to use LLVM or some other pre-made optimizer versus writing your own optimizations, which are tricky to get right. (<strong>Note</strong>: as @SK-logic says, this is technically not required for compilers, and you could implement optimizations in an interpreter. What I meant was that <em>users generally expect</em> optimizations in a compiler because then the extra compile step is &quot;worth it,&quot; but they don't expect them in interpreters. In fact, they often don't want them in interpreters because it slows down startup time <em>even more</em>, which loses the feedback loop advantage.)</li>
</ul>
</li>
<li><strong>It's easier to sandbox code in an interpreter.</strong> Of course, not every interpreter has sandboxing features, but it's still easier to do in an interpreter, and it is done at runtime, which means avoiding static analysis which is complicated, misses truly adversarial code, and had a lot of false positives. Honestly, I don't know why <em>every</em> interpreter doesn't have some sandboxing.</li>
</ul>
<h3>Cons</h3>
<ul>
<li><strong>Performance sucks.</strong> Developers need a reason to use your language. Now, performance is not that reason.
<ul>
<li><strong>It's easier to make things slower than needed.</strong> Related to the above, it's easier to write the interpreter in such a way that some or all operations are slow. Directly executing a custom AST? How much pointer chasing are you doing? I bet it's a lot.</li>
</ul>
</li>
<li><strong>You now have to convince end users to install an interpreter.</strong> Okay, they might have to install a compiler, <em>unless</em> developers ship binaries, but developers often <em>do</em> ship binaries to make install easy for the same reason you don't want to make end users install an interpreter: they want to reduce friction.</li>
<li><strong>Existing developer tools don't work.</strong> Better make them work or implement them yourself, which is more work. And that just sounds so <em>boring</em>.</li>
</ul>

CC BY-SA 4.0
2023-06-26T21:57:44.383Z
2023-06-26T22:46:38.567Z
2023-06-26T22:46:38.567Z
Gavin D. Howard
CC BY-SA 4.0
2023-06-26T22:25:10.023Z
You're not really obliged to do any optimisations in a compiler either. And nothing stops you from having very complex and costly optimisations in an interpreter.
SK-logic
CC BY-SA 4.0
2023-06-26T22:36:49.137Z
@SK-logic, you are correct, and I have added a note addressing that.
Gavin D. Howard
CC BY-SA 4.0
2023-11-18T15:39:45.547Z
Python is actually compiled first to bytecode, then executed by the Python VM. So, this optimizes startup and even allows statements to be simplified. Even so, Python acts like an interpreted language in many ways.
Schilive
# What are the pros and cons of interpreted programming languages?
Posted by: username_0 on 2023-06-21
Some programming languages are implemented via a source code interpreter instead of a compiler, for example Python, PHP, Ruby and Perl, and these programming languages are very popular.

So, this approach has many pros, but cons of course too.
Which are some pros/cons of interpreters?
**Tags:** implementation interpreters
> **Comments:**
> **username_1**: While I agree with @Adám, I feel this post could be more focused. You could maybe talk about the pros-cons of one specific technique; the question seems very broad as is. That being said, I'm not the one who downvoted, so the actual reason may be different.  
> **username_2**: Languages are not compiled or interpreted. Their implementations are.  
> **username_3**: @SK-logic many languages have specifications that make compilation either impractical or straight up impossible. Python for example brings heavy limitations if you want to use something like Cython or Numba to compile it.  
> **username_2**: @kouta-kun - impractical - yes, indeed, if the language is too dynamic, especially using dynamic scoping a lot, then you simply won't get any significant performance gains from compiling it. You still can compile it and get the same performance as interpreter does though. You can compile the said Python, see PyPy for example. There can be other reasons to compile, not just to get a better performance.  
> **username_3**: I'm now wondering if any programming language is truly "impossible" to compile, considering JIT as compilation, since like you said worst case you just have loads of runtime dispatch if dynamic typing is heavily used and strange scoping interactions, both of which can be worked around.  
> **username_2**: @kouta-kun Futamura projections says no, there is no language that cannot be compiled - at the very least you can always specialise an existing interpreter against a source code and it'll be an (inefficient) compilation, no matter what interpreter it is and how it works.  
> **username_4**: It's true that in principle every language can be both interpreted and compiled, as this is a property of an implementation of the language, not of the language itself. But also, many languages are designed to be interpreted, or designed to be compiled, so it's not meaningless to say "an interpreted language" and people generally understand what this means.  
> **username_5**: from the perspective of who? for what use-case? and compared to what?  
> **username_6**: @starball I think it's justifiable to leave both of the first two intentionally vague; that way answers can address the different factors that would go into making the decision, which is the real value of the pros-cons format.  
> **username_7**: What does the word "interpreted" mean in this question? As far as theory and implementations are concerned, a compiler _is_ an interpreter. In fact several implementations (and languages!) are designed so that a compiler and/or interpreter for a single language (ie. with no bytecode nor any other IR) exists both AoT and at runtime (Common Lisp, Clojure, Excelsior Jet, IKVM.NET, C++/CLI, D, JSP, JRuby, Quercus, ...).  
> **username_8**: Python doesn't use a source code interpreter. It's compiled into byte code, which is then interpreted.  
> **username_9**: I feel like this question has been asked a lot of times before…  
> **username_10**: This question is based on a massive and common misunderstanding. **Very few modern language implementations use source code interpreters.** What is extremely common is that they are **compiled to an intermediate form**, and then **the intermediate form is interpreted** in some form of VM. That leads to a **completely different set of pros and cons** making the question ambiguous to the point of uselessness.  
> **username_11**: @IMSoP indeed. Python is every bit as much "compiled" as Java or C#. It just also happens to offer a mode whereby individual statements can be compiled and immediately executed, in an environment that persists between such compilations.  
---
## 5 answers
### Answer by username_18 on 2023-06-26. Score: 13 | Accepted answer
I'll try to answer from the perspective of a language implementer/designer and as a user.

I'll also try to answer as broadly and generally as possible, but **disclaimer**: these lists may not apply to specific languages and implementations. And these lists will not be exhaustive.

## As a User

### Pros

* **Better guarantees about behavior.** An interpreter can more easily be written to make user code behave the same no matter what platform it runs on.
* **An interpreter is more likely to be available on many platforms.** This is not a guarantee, of course, but it's much simpler to port a well-written C, C++, Rust, etc., interpreter than it is to write a backend for yet another platform, especially when many platforms are much the same (you may have x64, but on Linux and Windows) with subtle and not-so-subtle differences.
  + **You can probably port the interpreter to a weird platform yourself.** Related to the portability of interpreters, you might be able to port it yourself, as a user, should that be necessary.
* **Your code can often avoid a compile step.** Another thing that is not a guarantee, but you may be able to skip compilation. This has many great effects:
  + **Faster feedback loop for development.**
  + **No need to recompile when you update a library.**
  + **No need for a complicated build process.** Okay, this one may not be true in some cases, but it does happen.

### Cons

* **Performance sucks.** The rule of thumb is that every layer of interpretation is one order of magnitude slower. This holds surprisingly well across many languages and implementations, so users basically have to assume their code will run 10x slower.
  + **More memory consumption.** Related to the above, when you run your program under an interpreter, you need memory for your program *and* for the interpreter.
  + **Startup time can be prohibitive.** Because this is something that had been a problem for several language implementations (JVM, Python, Julia, among others), I thought I'd better mention it specifically.
* **The interpreter is a runtime dependency.** You now have to install the interpreter on every machine where the code will run. Have fun.
* **Existing developer tools don't work.** You have to wait on the implementer or some driven soul to do it. Or do it yourself.

## As an Implementer

### Pros

* **It's much easier to make the language behave the same on diverse platforms.** No special hacks for weird platforms if your implementation language is good enough or has good enough libraries. (Personal note: I implemented a library of two's-complement arithmetic in portable C that avoids UB. This is some of my secret sauce to make C "good enough.")
  + **It's easier to define all behavior.** Undefined behavior is bad, and it makes users unhappy. With an interpreter, you can more easily define behaviors in your language and eschew the excuse for poor design that undefined behavior is.
* **It's easier to test.** With an interpreter, you're testing the same code on every platform modulo some small bits. With a compiler, you test a different backend for every platform.
* **Portability is as easy as you make it.** You can make it easy to port your interpreter to more platforms. [It all depends on you,](https://youtube.com/watch?v=ThMwHKfzz1I&t=65) not a finicky platform you don't control.
* **You don't need some general-ish AST format.** You can use whatever data structures make sense instead of transforming them into SSA, CPS, or some other form of IR that can enable optimization.
  + **You don't need to write optimizations for your language or to target a specific IR format.** Related to the above, you can depend on the optimizations of your implementation language and/or avoid the need to use LLVM or some other pre-made optimizer versus writing your own optimizations, which are tricky to get right. (**Note**: as @SK-logic says, this is technically not required for compilers, and you could implement optimizations in an interpreter. What I meant was that *users generally expect* optimizations in a compiler because then the extra compile step is "worth it," but they don't expect them in interpreters. In fact, they often don't want them in interpreters because it slows down startup time *even more*, which loses the feedback loop advantage.)
* **It's easier to sandbox code in an interpreter.** Of course, not every interpreter has sandboxing features, but it's still easier to do in an interpreter, and it is done at runtime, which means avoiding static analysis which is complicated, misses truly adversarial code, and had a lot of false positives. Honestly, I don't know why *every* interpreter doesn't have some sandboxing.

### Cons

* **Performance sucks.** Developers need a reason to use your language. Now, performance is not that reason.
  + **It's easier to make things slower than needed.** Related to the above, it's easier to write the interpreter in such a way that some or all operations are slow. Directly executing a custom AST? How much pointer chasing are you doing? I bet it's a lot.
* **You now have to convince end users to install an interpreter.** Okay, they might have to install a compiler, *unless* developers ship binaries, but developers often *do* ship binaries to make install easy for the same reason you don't want to make end users install an interpreter: they want to reduce friction.
* **Existing developer tools don't work.** Better make them work or implement them yourself, which is more work. And that just sounds so *boring*.
> **Comments:**
> **username_2** (2023-06-26): You're not really obliged to do any optimisations in a compiler either. And nothing stops you from having very complex and costly optimisations in an interpreter.  
> **username_18** (2023-06-26): @SK-logic, you are correct, and I have added a note addressing that.  
> **username_19** (2023-11-18): Python is actually compiled first to bytecode, then executed by the Python VM. So, this optimizes startup and even allows statements to be simplified. Even so, Python acts like an interpreted language in many ways.  
---
### Answer by username_2 on 2023-06-27. Score: 3
In addition to what was said in the other answers:

You'd normally design a language with typically interpreted semantics, as in - some form of a dynamic scoping, dynamic dispatch (probably, duck typing), some form of managed memory, etc., in case if you need a *scripting* language. An interactive language for a command line interface, for example, or embedded scripting language to control the behaviour of some application.

In such cases interpretation makes sense - firstly, most statements will only be executed once, so no need to waste time compiling them. Secondly, such languages often require very tight interoperability with the functionality of the host system, while code may not be trusted and may require sandboxing. Some believe both are easier to achieve with interpretation.

Having said that, the line between compilation and interpretation is very blurred, all the languages mentioned in the question are in fact bytecode-compiled, and there's quite a few interactive REPLs built on top of natively compiled languages (some Common Lisp implementations, for example).
> **Comments:**
> **username_4** (2023-06-27): Very few languages have [dynamic scopes](https://languagedesign.stackexchange.com/q/253/89) ─ typically, any language with a concept of scope will have lexical scopes. Perhaps the distinction you want to draw is between block scope (as in C or Java) and function scope (as in Python or Javascript).  
> **username_2** (2023-06-27): Both Python and Javascript have dynamic scoping (alongside with rudimentary forms of static scoping). So does elisp, even Common Lisp, Tcl, Perl and many many more.  
> **username_8** (2023-11-18): Python variables are lexically scoped by default, you have to use `global` and `nonlocal` to write to dynamically-scoped variables. Similar for Common Lisp; unless you declare a variable `special` it's lexically scoped.  
> **username_2** (2023-11-18): @Barmar Python scoping rules are weird, there's no nested lexical scoping within a single function definition, all variables share the same scope. I would not call it a proper lexical scoping. You can introduce a variable inside, say, an `if` branch and then use it outside.  
> **username_10** (2023-11-19): @SK-logic Just because an if block doesn't introduce a new scope, doesn't make the scopes which do exist "dynamic". In Python, function definitions can be nested, and when they are, it is the *lexically surrounding function* which provides the parent scope, not the *dynamic execution context*. Nor is it particularly "weird" - there are probably as many popular languages using function scope as using block scope.  
> **username_17** (2023-11-19): @IMSoP At the very least, I don't think it's as straightforward as "Python has lexical scoping". See the examples given in sections 4.2.2, 4.2.3 and 4.2.4 in [this paper](https://cs.brown.edu/~sk/Publications/Papers/Published/pmmwplck-python-full-monty/paper.pdf). They create a translation of Python into a lexically scoped language and talk about some of the scoping differences.  
> **username_10** (2023-11-19): @DavidYoung OK, but that's interesting, but a) not the same as "dynamic scoping", which is what the answer mentioned; b) not directly related to there being no block-level scope, which is what the comment I was responding to mentioned; and c) entirely unrelated to whether Python has "interpreted semantics" (whatever that means), exactly the same rules could be followed by a compiler - and, in fact, that's what happens, since contrary to the question no popular implementation of Python uses a "source code interpreter".  
> **username_2** (2023-11-20): @IMSoP do not forget that global variables in Python are dynamic, and this is one of the major impairments of the language. And this was a design decision made with interpretation assumed as default.  
> **username_10** (2023-11-20): @SK-logic I don't know what definition of "dynamic" you're using there, but it's surely not the one normally meant by "dynamic scope", because global variables have *no* scope, by definition. I'm also not sure what the relationship is with interpreter vs compiler implementations - I can't see any barrier to using a global variable in a fully compiled language. But then, I'm not sure what definition of "interpreter" you're thinking of either, since the question incorrectly refers to "source code interpreters", which is definitely not what either CPython or PyPy use.  
> **username_2** (2023-11-20): @IMSoP dynamic scoping similar to, say, elisp. If you're designing a language for an interpreter, you'll be ok with looking up a variable in some table every single time it's referenced. If you're designing a language straight away for an efficient compilation, you'll think twice before introducing such semantics. Also, since the OP used the term "source code interpreter" incorrectly, I simply assumed they're talking about any kind of interpreter in general.  
> **username_10** (2023-11-20): @SK-logic Unfortunately, I don't know elisp, so that doesn't help; but from what you're saying,  it sounds like you're talking about dynamic *allocation* - i.e. being able to *create* global variables from anywhere? The *scope* of such a variable is still "global", but it's *extent* or *lifetime* is shorter; unlike in, say, C, where a global variable is *statically allocated* and thus has both scope and lifetime of the whole program. It would be possible, but I agree unusual, for a language to compile `global foo;` wherever it occurred into a global static allocation (a kind of "hoisting").  
> **username_2** (2023-11-20): @IMSoP no, I am talking about dynamic scoping, which is, in this case, dynamic lookup. Every time the dynamically scoped name is referenced it is looked up again, and can be found in different places every single time. Static scoping means one name in one context always refers to one well defined origin.  
> **username_10** (2023-11-20): @SK-logic Then I'm not following at all. In what way can a global variable "be found in different places every single time"? You can't "shadow" one global variable with another global variable; it's global. You can access a variable which hasn't been initialised yet, but that's semantically the same as in any static scope where you don't have to declare variables before the first line of procedural code. It can have different *values*, and those values might be dynamically *typed*, but that's not the same as mapping the name to a different variable.  
> **username_2** (2023-11-20): @IMSoP there's a dictionary returned by `globals()`, and Python implementations are expected to respect whatever you'll do with it. This very severely limits the ability of Python compilers to optimise an access to global variables, they must be looked up every single time.  
> **username_10** (2023-11-20): @SK-logic That's not "dynamic scoping", though; whenever you access it, the global variable "foo" points to the entry in that dictionary called "foo"; it won't sometimes point to a different entry, or a different dictionary. That entry might be "missing", but that's really just a special value - it will be missing for *everything* that calls it, until it's assigned a new value, then *everything* will see the value.  
> **username_2** (2023-11-20): @IMSoP this is exactly how dynamic scoping works in the other dynamically scoped languages. And yes, this entry can point to different origins of the `foo` definition every time you call a function that refers to it. You cannot compile it once and replace with a pointer. You must look it up in the dictionary every single time.  
> **username_10** (2023-11-20): @SK-logic I still don't understand what you mean by "different origins of the `foo` definition every time". If there's a single dictionary, then at any moment, it has exactly one entry with a key of `foo`; that's the same as any symbol table, whether it's global, function-local, block-local, etc. Outside of global scope, you have multiple dictionaries (one for each scope), each of which can have its own `foo` *simultaneously*; dynamic scoping means that you choose *between those dictionaries* based on the calling context of the function, *before* looking up the key `foo` in that dictionary.  
> **username_10** (2023-11-21): Let us [continue this discussion in chat](https://chat.stackexchange.com/rooms/149825/discussion-between-imsop-and-sk-logic).  
---
### Answer by username_12 on 2023-11-20. Score: 1
An issue I've not seen mentioned yet is that interpreters may be subdivided into multiple categories. Some receive input from a stream, individually processing commands contained therein. Some execute exclusively from data structures which must be pre-loaded before program execution starts. Some are capable of executing directly from a stream, or from objects constructed by the execution of previous commands. The first and third categories may be useful in cases where it may be necessary to start executing parts of a program before the entire program exists (or in some situations, where no "complete program" will ever exist, because each command will be jettisoned from memory after it executes).

Additionally, some interpreters are designed to process source text that would be created by a human or other entity that is designed to produce program source text to accomplish some *particular* objective, while others are designed to act upon programs which have been first fed through a "transpiler" that might convert e.g. `x=y+z;` into a sequence of bytes whose meaning might be described as e.g. "pushIntVariable #4; pushIntVariable #7; Add; pushAddressOfVariable #9; StoreInt". An interpreter given a such sequence of bytes could avoid having to spend time on things like symbol-table lookup, and thus run must faster than one which must fully parse everything every time it is encountered.

While some tools that are used to run programs are clearly "compilers", and others are clearly "interpreters", there are many that end up sharing characteristics of both.
> **Comments:**
> **username_10** (2023-11-20): Upvoted mostly for the last sentence. Dividing languages / implementations into two camps of "compiled" and "interpreted" stopped being useful decades ago.  
---
### Answer by username_13 on 2023-11-18. Score: 1
The ability to product self-modifying code, such as by producing strings that are then executed as if they are a piece of code of said language, are trivial to do in an interpreted language, but not so much in a compiled language.

There is a reason why Python has `exec()`, JavaScript has the `Function()` constructor function, and Lua has `loadstring()`, but C or C++ has no such equivalent. In a compiled language, the only way would be to force the language standard library to include a compiler for said language, which would bloat the language considerably. But in an interpreted language, the interpreter is already there so such constructs are trivially implemented as 'invoke the interpreter on the contents of this string.'
---
### Answer by username_14 on 2023-06-26. Score: 0
# PROS

1. Quicker development. Obviously a good thing. There simpler and have dynamic typing which speeds up developemnt. They also have high-level data structures.
2. Easier debugging. It is more interactive which allows for this. They can experiment with code snippets without a compile build run cycle thats separate.
3. Simplicity. There is more straightforward syntax and expressive constructs. This is ovbiously good and makes it more readable as well as easy to learn.

# CONS

1. Worse performance. The code is translated and executed line by line at the runtime and this causes the performance hit. JIT improves it to some extent but not fully.
2. Development complexity. While its simple to use it is quite hard to make. They might need language runtime or an interpreter.
> **Comments:**
> **username_4** (2023-06-26): Dynamic typing and late binding are two separate concepts. You can have static typing and late binding (e.g. methods in Java), or dynamic typing and early binding (e.g. local variables in Python).  
> **username_15** (2023-06-26): It's not clear to me that *any* of these points is fully accurate, if at all. Most of them don't seem to be related to interpretation, and one of the ones that is says "[an interpreted language] might need [...] an interpreter". At the least, the answer could benefit from adding explanation and justification to each of the claims.  
> **username_16** (2023-07-02): All of the pros can be applied to a compiled language, if designed properly. Dynamic typing may even *slow down* development by introducing hard to find type errors  
---
