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, 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.
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, 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.
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).
Blatant copy from wikipedia so I'll make this community wiki.
Advantages of interpreted languages
Interpreted languages give programs certain extra flexibility over compiled languages. Features that are easier to implement in interpreters than in compilers include (but are not limited to):
- platform independence (Java's byte code, for example)
- reflection and reflective usage of the evaluator (e.g. a first-order eval function)
- dynamic typing
- ease of debugging (it is easier to get source code information in interpreted languages)
- small program size (since interpreted languages have flexibility to choose instruction code)
- dynamic scoping
- automatic memory management
Disadvantages of interpreted languages
An execution by an interpreter is usually much less efficient than regular program execution. It happens because either every instruction should pass an interpretation at runtime or as in newer implementations, the code has to be compiled to an intermediate representation before every execution. The virtual machine is a partial solution to the performance issue as the defined intermediate-language is much closer to machine language and thus easier to be translated at run-time. Another disadvantage is the need for an interpreter on the local machine to make the execution possible.
Pros:
- Rapid prototyping (no write, compile, execute cycle)
- Cross-platform (assuming interpreters exist for each platform)
Cons:
- Performance (won't be as fast as compiled languages)
What are the advantages of using an interpreted language?
One advantage is that you can write code and see the results immediately, making it great for prototyping and iterative development. Interpreted languages also tend to have simpler syntax and are often easier to learn compared to compiled languages.
What is an interpreted language?
An interpreted language is a programming language that executes instructions directly, without the need for a separate compilation step. The instructions are translated and executed line by line, making it easier and quicker to develop and test code.
Which programming languages are commonly interpreted?
Some popular interpreted languages include Python, JavaScript, Ruby, Perl, and PHP. These languages are widely used in web development, scripting, and automation tasks due to their ease of use and quick development process.
Videos
There is no hard line
There are various techniques that blend the line between compiled and interpreted languages various techniques blur the line, like:
- JIT compilation
- Interpreting bytecode
- Virtual Machines
- Runtime Libraries
- and much more
Still there is a sliding scale of how much work you do at compile time and how much you do at run time.
Some benefits from doing things ahead of time are:
- Code is generally faster to run
- Interpreted code can get some of these benefits too with JIT or bytecode
- Can run natively without requiring users of a program to download something extra
- Can be mitigated by building executables that embed the interpreter, eg. py2exe
However, it also comes with downsides:
- Compiling takes time, thus slowing down iteration time during development
- Compiled code needs to be built specifically for every platform it's intended to run on, while interpreted code can run on any platform with a interpreter available
- Can be mitigated with virtual machines
Overall you can quite easily mix and match what interpreted or compiled features you like best.
Interpreted Language Advantage
- Portability: Programs written in interpreted languages can be transferred as source code (or bytecode) to different platforms that have the interpreter implemented, without having to change the program.