关于解释器:如果Ruby的所有实现都被编译成字节码,那么Ruby真的是一种解释型语言吗?

Is Ruby really an interpreted language if all of its implementations are compiled into bytecode?

在这个关于蓝宝石的问题的答案中,查克说:

All of the current Ruby
implementations are compiled to
bytecode. Contrary to SAP's claims, as
of Ruby 1.9, MRI itself includes a
bytecode compiler, though the ability
to save the compiled bytecode to disk
disappeared somewhere in the process
of merging the YARV virtual machine.
JRuby is compiled into Java .class
files. I don't have a lot of details
on MagLev, but it seems safe to say it
will take that road as well.

我对这个关于Ruby的编译/解释问题感到困惑。

我了解到Ruby是一种解释性语言,所以当我保存对Ruby文件的更改时,不需要重新构建项目。

但是,如果现在所有的Ruby实现都被编译了,那么说Ruby是一种解释语言是否公平呢?或者我误解了什么?


如果你把字节码算作正在编译的话,现在几乎每种语言都是"编译"的。甚至EmacsLisp也被编译。Ruby是一个特殊的例子,因为直到最近,它还没有编译成字节码。

我认为你对将语言描述为"编译"与"解释"的效用提出质疑是正确的。不过,一个有用的区别是,语言是否直接从用户代码创建机器代码(例如x86汇编程序)。C,C++,很多LISPS,JAVA支持JIT,但是Ruby、Python和Perl不这样做。

不太了解的人会将任何有单独的手动编译步骤的语言称为"已编译"和"未解释"。


是的,Ruby仍然是一种被解释的语言,或者更准确地说,Matz的Ruby解释器(MRI)仍然是一种解释器,当人们谈论Ruby时通常都会谈论到它。编译步骤只是为了将代码减少到比一次又一次地解释和重新解释相同代码更快的执行速度。


一个微妙的问题…过去,"解释的"语言被解析并转换成一种执行速度更快的中间形式,但执行它们的"机器"是一个相当特定于语言的程序。编译的语言被翻译成运行它的计算机所支持的机器代码指令。早期的区别是非常基本的——静态与动态范围。在静态类型语言中,变量引用几乎可以在几个机器指令中解析为内存地址——您确切知道变量在调用帧中引用的位置。在动态类型语言中,您必须搜索(向上搜索a-list或向上搜索调用帧)以获取引用。随着面向对象编程的出现,引用的非即时性扩展到了更多的概念——类(类型)、方法(函数),甚至语法解释(如regex等嵌入式DSL)。

事实上,追溯到70年代后期,编译语言和解释语言之间的区别并不是很大,而是它们是在编译或解释环境中运行的。例如,Pascal(我学习的第一种高级语言)在加州大学伯克利分校首先使用了BillJoy的PxP解释器,后来又使用了编写PCC的编译器。相同的语言,在编译和解释环境中都可用。

有些语言比其他语言更具动态性,某种东西的含义——类型、方法、变量——取决于运行时环境。这意味着不管是否编译,都有与执行程序相关的大量运行时机制。第四,smalltalk、news、lisp都是这样的例子。最初,这些语言需要大量的机制来执行(相对于C或Fortran),因此它们是一种自然的解释方式。

甚至在Java之前,人们曾试图通过技巧、线程化编译、即时编译等技术来加速复杂、动态语言的执行。

我认为它是Java,它是第一个广泛传播的语言,它真的把编译器/解释者的间隙弄糊涂了,讽刺的是,它不能运行得更快(尽管如此),但是它会到处运行。通过定义自己的机器语言和"机器"Java字节码和VM,Java试图成为一种编译成接近任何基本机器的语言,但实际上不是任何真正的机器。

现代语言结合了所有这些创新。有些语言具有动态的、开放式的、您不知道的传统"解释语言"(ruby、lisp、smalltalk、python、perl(!)的运行前性质)有些尝试具有严格的规范,允许基于传统的编译语言(Java,Scala)的基于深度类型的静态错误检测。所有这些都编译为实际的独立于机器的表示(JVM),以便在任何地方运行一次即写的语义。

那么,编译与解释?我想说,两者兼而有之。所有的代码都在源代码中(包括文档),改变任何东西,并且效果是即时的,简单的操作运行速度几乎和硬件可以做到的一样快,支持复杂的操作并且速度足够快,硬件和内存模型跨平台是一致的。

今天语言中更大的争论可能是它们是静态类型还是动态类型,也就是说,它们运行的速度有多快,但是编译器是否会事先发现错误(以程序员必须指定相当复杂的类型信息为代价),或者错误会在测试和生产中出现。


编译语言通常编译成机器代码,而不仅仅是字节代码。但是,有些字节代码生成器实际上可以将字节代码进一步编译为机器代码。

字节码本身只是用户编写的文字代码和虚拟机之间的中间步骤,但它仍然需要由虚拟机来解释(尽管它是用Java在JVM和PHP中用操作码缓存完成的)。


您可以使用IRB(交互式Ruby Shell)以交互方式运行Ruby程序。虽然它可以生成中间字节码,但在传统意义上它肯定不是一个"编译器"。


至于我从2011年在上海的RubyConf获得的信息,Matz正在开发一个"mruby"(代表Matz的Ruby)来瞄准在嵌入式设备上运行的目标。Matz说,mruby将提供将ruby代码编译成机器代码的能力,以提高速度并减少(有限)资源在嵌入式设备上的使用。所以,有各种各样的Ruby实现,当然不是所有的实现都是在运行时解释的。


这可能有点离题,但…

IronRuby是Ruby的一个基于.NET的实现,因此通常编译为字节代码,然后在运行时编译为机器语言(即不解释)。另外(至少对于其他.NET语言,我假设是Ruby语言),可以提前使用NGen生成已编译的本机二进制文件,因此这实际上是Ruby代码的机器代码编译版本。