1
$\begingroup$

Are there any languages that are interpreted in something interpreted, like Python? If so, what are the advantages?

$\endgroup$
3
  • $\begingroup$ Arguably languages implemented in a JVM language are intepreted, though I digress $\endgroup$
    – Seggan
    Nov 4, 2023 at 18:26
  • 3
    $\begingroup$ Many toy and/or golfing languages are implemented in Python or JavaScript $\endgroup$
    – Seggan
    Nov 4, 2023 at 18:26
  • 2
    $\begingroup$ I do not see any advantages other than 'ease' of writing an implementation if writing an interpreter in an interpreted language is somehow easier than with a compiled language. $\endgroup$ Nov 4, 2023 at 19:11

3 Answers 3

7
$\begingroup$

Many interpreters are written in interpreted languages; this is really a property of the implementation rather than the language. The advantage generally is to be able to use that host language for implementing the other, for convenience, existing knowledge, or particular features of the language that make it suitable for implementing other languages. These are just the same reasons you might use those languages for any other program too.

Implementing an interpreter under an interpreter isn’t generally either easier or harder than implementing it under a compiler. The host language could be implemented either way (and sometimes there are implementations both ways — like Python!), and typical interpreters could run on any implementation of the language they’re written in. The short answer is then that yes, they can be and are built that way, but no, there’s no strong reason in general to do it one way or the other.


While there’s generally no inherent difference to an interpreter in an interpreted language, there are a few situations where it can be relevant:

  • Metacircular interpreters are a style of interpreter implemented within the language they’re interpreting, leveraging the host language’s functionality to execute code. These aren’t necessarily built on top of interpreters, but interpreters do often expose more reflective facilities to do this, and sometimes you can stack nesting dolls of interpreters this way.
  • Domain-specific languages used for things like configuration and special-purpose business logic within a program are generally interpreted, and implemented in the host language of that program. Some implementation strategies are more viable in interpreters, and that can make creating the DSL in the first place more likely.
  • Prototyping or exploratory language design within an interpreter can be more convenient if only for avoiding compile cycles, but dynamic eval in particular is very rare in compilers and can be useful.
  • Languages targeting platforms built around interpreted languages, like the web, need to conform to that restriction.
  • Bytecode systems are interpreted, from a certain point of view, so you could argue that all languages compiling to those are interpreted; it’s harder to distinguish the standard Java, C#, Python, and JavaScript implementations from this perspective than you might first think, and there are many interpreters written in the first two as well. This is quibbling semantics, however.

I have written many interpreters in both (typically-) compiled and interpreted languages. The reasons for one or another have all been external, determined by other systems I was working with or my whims and preferences at the time, and could have been overcome if something had been a little different. That is also the case in general: other factors dominate the decision rather than the implementation strategy of the host language.

$\endgroup$
3
$\begingroup$

Languages aren't interpreted. Nor are they compiled. Languages just are.

The term "interpreted language" is non-sensical. It is a category error. Shriram Krishnamurthi once said in an interview something like "if English were a typed language, 'interpreted language' would be a type error".

A particular implementation of a language may use interpretation or compilation (or, in most modern mainstream high-performance implementations, likely both), but that is purely a trait of the implementation, not the language.

Therefore, the question doesn't make sense.

Every language can be implemented by an interpreter. Every language can be implemented by a compiler. You can automatically derive a compiler from an interpreter. You can easily derive an interpreter from a compiler.

The vast majority of modern mainstream languages have both interpreted and compiled implementations.

One possible interpretation of the question is: "has there ever been an instance where there were two levels of interpretation", and the answer is that this happens all the time. In fact, a CPU is nothing but an interpreter for its instruction set, so every time you run a natively compiled interpreter, you are using two levels of interpretation. E.g., when you run a Python program in CPython, CPython first compiles the Python program into CPython byte code, then it interprets this CPython byte code, whilst itself being interpreted by the CPU.

If you think that calling the CPU an interpreter is cheating, you can use an emulator such as JPC, TinyEMU, JSLinux, jor1k, v86, Angel, QEmu, or many others.

Or, a much simpler argument: many interpreters are written in C. There are interpreters for C. Ergo, you can run an interpreter written in C on an interpreter for C.

$\endgroup$
1
  • 2
    $\begingroup$ This is a little pedantic. While compilation and interpretation and "language" are overused and underspecified, sure, it's pretty clear the OP is talking about implementations of languages in a language that itself is implemented in a bytecode interpreter or higher. $\endgroup$
    – apropos
    Nov 5, 2023 at 2:45
2
$\begingroup$

One issue not mentioned in the other answers so far is garbage collection.

As already mentioned, being "interpreted" is a property of a language implementation, not a property of the language itself, as the same language could have both a compiler and an interpreter. However, we can talk about dynamic languages, i.e. those with features like dynamic types, runtime type checks or duck typing, construction of new types at runtime, and especially mechanisms like eval or exec which evaluate code from strings at runtime. Dynamic languages tend to be implemented as interpreters, though there are several notable exceptions.

Dynamic languages also tend to be garbage-collected. So, when you are implementing an interpreter for a dynamic language, there is a benefit to writing it in another dynamic language, since your interpreter will naturally take advantage of the garbage collection in the host language. In contrast, if you are writing a compiler (to a target like an assembly language, or LLVM IR), then you will need to explicitly implement garbage collection. That said, a compiler targeting another dynamic language (e.g. compiling Python to Javascript) would also get garbage collection "for free".

$\endgroup$
2
  • $\begingroup$ "Dynamic languages tend to be implemented as interpreters" – Do they? All mainstream Python implementations, Ruby implementations, and ECMAScript implementations have compilers, as do PHP and Erlang. The last mainstream dynamic language implementation I can remember being interpreted was Ruby's MRI, which has been obsolete for 10 years now. Its successor, YARV, has a compiler. The only dynamic languages I can think of which have mainly interpreted implementations are shells like Bash and Zsh and DSLs like Sed, Ed, Awk, etc. $\endgroup$ Nov 5, 2023 at 1:18
  • $\begingroup$ @JörgWMittag If you are only talking about mainstream languages then that is true, to an extent; CPython is both a compiler to CPython bytecode, and a bytecode interpreter, for example. $\endgroup$
    – kaya3
    Nov 5, 2023 at 12:27

Not the answer you're looking for? Browse other questions tagged .