我想更好地理解其中的区别。我在网上找到了很多解释,但它们都倾向于抽象的差异,而不是实际的含义。

Most of my programming experiences has been with CPython (dynamic, interpreted), and Java (static, compiled). However, I understand that there are other kinds of interpreted and compiled languages. Aside from the fact that executable files can be distributed from programs written in compiled languages, are there any advantages/disadvantages to each type? Oftentimes, I hear people arguing that interpreted languages can be used interactively, but I believe that compiled languages can have interactive implementations as well, correct?


当前回答

首先,澄清一下,Java不是完全静态编译和以c++的方式链接的。它被编译成字节码,然后由JVM解释。JVM可以对本机机器语言进行即时编译,但不必这样做。

更重要的是:我认为交互性是主要的实际区别。由于所有内容都是解释的,所以您可以截取一小段代码,解析并根据环境的当前状态运行它。因此,如果您已经执行了初始化变量的代码,则可以访问该变量,等等。它真的很适合函数式风格。

然而,解释成本很高,特别是当您有一个包含大量引用和上下文的大型系统时。根据定义,这是一种浪费,因为相同的代码可能必须解释和优化两次(尽管大多数运行时都为此进行了缓存和优化)。不过,您仍然需要支付运行时成本,并且经常需要运行时环境。您也不太可能看到复杂的过程间优化,因为目前它们的性能还没有充分的交互性。

因此,对于不会有太大变化的大型系统,以及某些语言,更有意义的是预编译和预链接所有内容,做所有可以做的优化。最终会得到一个非常精简的运行时,该运行时已经针对目标机器进行了优化。

至于生成可执行文件,恕我直言,这一点关系不大。通常可以从编译语言创建可执行文件。但是您也可以使用解释语言创建可执行文件,只不过解释器和运行时已经打包在可执行文件中,并且对您隐藏了。这意味着您通常仍然需要支付运行时成本(尽管我确信对于某些语言,有方法将所有内容转换为可执行树)。

我不同意所有的语言都可以互动。某些语言,如C语言,与机器和整个链接结构紧密相连,我不确定您是否能够构建一个有意义的完整的交互式版本

其他回答

语言本身既不编译也不解释,只有语言的特定实现才是。Java就是一个很好的例子。有一个基于字节码的平台(JVM)、一个本机编译器(gcj)和一个用于Java超集(bsh)的互用器。那么Java现在是什么呢?字节码编译,本机编译还是解释?

其他既编译又解释的语言有Scala、Haskell或Ocaml。每种语言都有一个交互式解释器,以及一个字节码或本机机器码的编译器。

所以一般来说,用“编译型”和“解释型”来划分语言并没有多大意义。

首先,澄清一下,Java不是完全静态编译和以c++的方式链接的。它被编译成字节码,然后由JVM解释。JVM可以对本机机器语言进行即时编译,但不必这样做。

更重要的是:我认为交互性是主要的实际区别。由于所有内容都是解释的,所以您可以截取一小段代码,解析并根据环境的当前状态运行它。因此,如果您已经执行了初始化变量的代码,则可以访问该变量,等等。它真的很适合函数式风格。

然而,解释成本很高,特别是当您有一个包含大量引用和上下文的大型系统时。根据定义,这是一种浪费,因为相同的代码可能必须解释和优化两次(尽管大多数运行时都为此进行了缓存和优化)。不过,您仍然需要支付运行时成本,并且经常需要运行时环境。您也不太可能看到复杂的过程间优化,因为目前它们的性能还没有充分的交互性。

因此,对于不会有太大变化的大型系统,以及某些语言,更有意义的是预编译和预链接所有内容,做所有可以做的优化。最终会得到一个非常精简的运行时,该运行时已经针对目标机器进行了优化。

至于生成可执行文件,恕我直言,这一点关系不大。通常可以从编译语言创建可执行文件。但是您也可以使用解释语言创建可执行文件,只不过解释器和运行时已经打包在可执行文件中,并且对您隐藏了。这意味着您通常仍然需要支付运行时成本(尽管我确信对于某些语言,有方法将所有内容转换为可执行树)。

我不同意所有的语言都可以互动。某些语言,如C语言,与机器和整个链接结构紧密相连,我不确定您是否能够构建一个有意义的完整的交互式版本

解释源代码相对于编译源代码的最大优势是可移植性。

如果你的源代码是编译的,你需要为你的程序运行在不同类型的处理器和/或平台编译不同的可执行文件(例如一个用于Windows x86,一个用于Windows x64,一个用于Linux x64,等等)。此外,除非您的代码完全符合标准,并且不使用任何特定于平台的函数/库,否则您实际上需要编写和维护多个代码库!

如果你的源代码是解释型的,你只需要编写一次,它就可以在任何平台上由合适的解释器解释和执行!它是便携!请注意,解释器本身是为特定平台编写和编译的可执行程序。

编译代码的一个优点是它向最终用户隐藏了源代码(可能是知识产权),因为您部署的不是人类可读的原始源代码,而是一个模糊的二进制可执行文件。

简短的(不精确的)定义:

编译语言:将整个程序立即转换为机器代码,然后由CPU运行机器代码。

解释语言:逐行读取程序,一旦读取一行,CPU就会执行该行的机器指令。

但实际上,现在很少有语言是纯编译或纯解释的,它们通常是混合的。想要更详细的图片描述,请看这个帖子:

编译和解释的区别是什么?

或者是我后来的博客:

https://orangejuiceliberationfront.com/the-difference-between-compiler-and-interpreter/

从http://www.quora.com/What-is-the-difference-between-compiled-and-interpreted-programming-languages

There is no difference, because “compiled programming language” and “interpreted programming language” aren’t meaningful concepts. Any programming language, and I really mean any, can be interpreted or compiled. Thus, interpretation and compilation are implementation techniques, not attributes of languages. Interpretation is a technique whereby another program, the interpreter, performs operations on behalf of the program being interpreted in order to run it. If you can imagine reading a program and doing what it says to do step-by-step, say on a piece of scratch paper, that’s just what an interpreter does as well. A common reason to interpret a program is that interpreters are relatively easy to write. Another reason is that an interpreter can monitor what a program tries to do as it runs, to enforce a policy, say, for security. Compilation is a technique whereby a program written in one language (the “source language”) is translated into a program in another language (the “object language”), which hopefully means the same thing as the original program. While doing the translation, it is common for the compiler to also try to transform the program in ways that will make the object program faster (without changing its meaning!). A common reason to compile a program is that there’s some good way to run programs in the object language quickly and without the overhead of interpreting the source language along the way. You may have guessed, based on the above definitions, that these two implementation techniques are not mutually exclusive, and may even be complementary. Traditionally, the object language of a compiler was machine code or something similar, which refers to any number of programming languages understood by particular computer CPUs. The machine code would then run “on the metal” (though one might see, if one looks closely enough, that the “metal” works a lot like an interpreter). Today, however, it’s very common to use a compiler to generate object code that is meant to be interpreted—for example, this is how Java used to (and sometimes still does) work. There are compilers that translate other languages to JavaScript, which is then often run in a web browser, which might interpret the JavaScript, or compile it a virtual machine or native code. We also have interpreters for machine code, which can be used to emulate one kind of hardware on another. Or, one might use a compiler to generate object code that is then the source code for another compiler, which might even compile code in memory just in time for it to run, which in turn . . . you get the idea. There are many ways to combine these concepts.