如果 Ruby 的所有实现都编译为字节码,那么它真的是一种解释性语言吗?
在为 这个选择的答案中关于 Blue Ruby 的问题,Chuck 说:
所有当前的 Ruby 实现被编译为 字节码。 与 SAP 的说法相反, Ruby 1.9 中,MRI 本身包括 字节码编译器,虽然能力 将编译后的字节码保存到磁盘 在此过程中某处消失 合并 YARV 虚拟机。 JRuby被编译成Java .class 文件。 我没有太多细节 关于磁悬浮列车,但似乎可以肯定地说 也会走那条路。
我对 Ruby 的编译/解释问题感到困惑。
我了解到 Ruby 是一种解释性语言,这就是为什么当我保存对 Ruby 文件的更改时,我不需要重新构建项目。
但是,如果现在所有 Ruby 实现都是编译的,那么说 Ruby 是一种解释性语言还公平吗? 或者我误解了什么?
In the chosen answer for this question about Blue Ruby, Chuck says:
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.
I'm confused about this compilation/interpretation issue with respect to Ruby.
I learned that Ruby is an interpreted language and that's why when I save changes to my Ruby files I don't need to re-build the project.
But if all of the Ruby implementations now are compiled, is it still fair to say that Ruby is an interpreted language? Or am I misunderstanding something?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
如果你把字节码算作编译的话,现在几乎所有语言都是“编译的”。 甚至 Emacs Lisp 也是编译的。 Ruby 是一个特例,因为直到最近,它还没有被编译成字节码。
我认为你对将语言描述为“编译”与“解释”的效用提出质疑是正确的。 不过,一个有用的区别是该语言是否直接从用户代码创建机器代码(例如 x86 汇编程序)。 C、C++、许多 Lisp 和启用了 JIT 的 Java 都可以,但 Ruby、Python 和 Perl 则不然。
不太了解的人会将任何具有单独手动编译步骤的语言称为“编译”,而将没有的语言称为“解释”。
Nearly every language is "compiled" nowadays, if you count bytecode as being compiled. Even Emacs Lisp is compiled. Ruby was a special case because until recently, it wasn't compiled into bytecode.
I think you're right to question the utility of characterizing languages as "compiled" vs. "interpreted." One useful distinction, though, is whether the language creates machine code (e.g. x86 assembler) directly from user code. C, C++, many Lisps, and Java with JIT enabled do, but Ruby, Python, and Perl do not.
People who don't know better will call any language that has a separate manual compilation step "compiled" and ones that don't "interpreted."
是的,Ruby 仍然是一种解释性语言,或者更准确地说,Matz 的 Ruby Interpreter (MRI),也就是人们在谈论 Ruby 时通常所说的,仍然是一种解释器。 编译步骤只是为了将代码简化为比一次又一次解释和重新解释相同代码执行速度更快的代码。
Yes, Ruby's still an interpreted language, or more precisely, Matz's Ruby Interpreter (MRI), which is what people usually talk about when they talk about Ruby, is still an interpreter. The compilation step is simply there to reduce the code to something that's faster to execute than interpreting and reinterpreting the same code time after time.
确实是一个微妙的问题...
过去,“解释型”语言被解析并转换为执行速度更快的中间形式,但执行它们的“机器”是一个漂亮的特定于语言的程序。 “编译”语言被翻译成运行它的计算机支持的机器代码指令。 早期的区别是非常基本的——静态作用域与动态作用域。 在静态类型语言中,变量引用几乎可以解析为一些机器指令中的内存地址——您确切地知道变量在调用框架中引用的位置。 在动态类型语言中,您必须搜索(向上查找 A-list 或向上调用框架)以获取参考。 随着面向对象编程的出现,引用的非直接性质扩展到更多概念——类(类型)、方法(函数),甚至语法解释(嵌入式 DSL,如正则表达式)。
事实上,也许可以追溯到 70 年代末,编译语言和解释语言之间的区别并不在于它们之间的区别,而在于它们是在编译环境中运行还是在解释环境中运行。
例如,Pascal(我学习的第一种高级语言)首先在加州大学伯克利分校的 Bill Joy 的 pxp 解释器上运行,后来在他编写的 pcc 编译器上运行。 相同的语言,可在编译和解释环境中使用。
有些语言比其他语言更具动态性,某些东西(类型、方法、变量)的含义取决于运行时环境。 这意味着无论是否编译,都存在与执行程序相关的大量运行时机制。 Forth、Smalltalk、News、Lisp,都是这样的例子。 最初,这些语言需要如此多的机制来执行(相对于 C 或 Fortran),因此它们很适合解释。
甚至在 Java 出现之前,就有人尝试通过技巧、技术来加速复杂的动态语言的执行,这些技巧、技术后来成为线程编译、即时编译等。
不过,我认为是 Java,它是第一个广泛传播的语言,真正混淆了编译器/解释器的差距,具有讽刺意味的是,它不是为了运行得更快(尽管如此),而是为了让它可以在任何地方运行。 通过定义自己的机器语言并“机器”java字节码和VM,Java试图成为一种编译成接近任何基本机器的语言,但实际上不是任何真实的机器。
现代语言结合了所有这些创新。 有些具有传统“解释型语言(ruby、lisp、smalltalk、python、perl(!))”的动态、开放式、直到运行时才知道什么的性质,有些则尝试具有严格的规范,允许对传统编译语言(java、scala)进行基于深度类型的静态错误检测。所有这些都编译为实际的与机器无关的表示(JVM)以获得“一次编写,随处运行”的语义。
那么,编译还是解释?我想说,最好的是,所有代码都在源代码中(带有文档),更改任何内容,效果都是立竿见影的,简单的操作运行得几乎与硬件一样快,支持复杂的操作并且速度足够快,硬件。 当今语言
中更大的争论可能是它们是静态类型还是动态类型,也就是说不是它们运行的速度有多快,而是编译器会提前发现错误(代价是程序员必须指定相当复杂的类型信息)或者在测试和生产中会出现错误。
A subtle question indeed...
It used to be that "interpreted" languages were parsed and transformed into an intermediate form which was faster to execute, but the "machine" executing them was a pretty language specific program. "Compiled" languages were translated instead into the machine code instructions supported by the computer on which it was run. An early distinction was very basic--static vs. dynamic scope. In a statically typed language, a variable reference could pretty much be resolved to a memory address in a few machine instructions--you knew exactly where in the calling frame the variable referred. In dynamically typed languages you had to search (up an A-list or up a calling frame) for the reference. With the advent of object oriented programming, the non-immediate nature of a reference expanded to many more concepts--classes(types), methods(functions),even syntactical interpretation (embedded DSLs like regex).
The distinction, in fact, going back to maybe the late 70's was not so much between compiled and interpreted languages, but whether they were run in a compiled or interpreted environment.
For example, Pascal (the first high-level language I studied) ran at UC Berkeley first on Bill Joy's pxp interpreter, and later on the compiler he wrote pcc. Same language, available in both compiled and interpreted environments.
Some languages are more dynamic than others, the meaning of something--a type, a method, a variable--is dependent on the run-time environment. This means that compiled or not there is substantial run-time mechanism associated with executing a program. Forth, Smalltalk, NeWs, Lisp, all were examples of this. Initially, these languages required so much mechanism to execute (versus a C or a Fortran) that they were a natural for interpretation.
Even before Java, there were attempts to speed up execution of complex, dynamic languages with tricks, techniques which became threaded compilation, just-in-time compilation, and so on.
I think it was Java, though, which was the first wide-spread language that really muddied the compiler/interpreter gap, ironically not so that it would run faster (though, that too) but so that it would run everywhere. By defining their own machine language and "machine" the java bytecode and VM, Java attempted to become a language compiled into something close to any basic machine, but not actually any real machine.
Modern languages marry all these innovations. Some have the dynamic, open-ended, you-don't-know-what-you-get-until-runtime nature of traditional "interpreted languages (ruby, lisp, smalltalk, python, perl(!)), some try to have the rigor of specification allowing deep type-based static error detection of traditional compiled languages (java, scala). All compile to actual machine-independent representations (JVM) to get write once-run anywhere semantics.
So, compiled vs. interpreted? Best of both, I'd say. All the code's around in source (with documentation), change anything and the effect is immediate, simple operations run almost as fast as the hardware can do them, complex ones are supported and fast enough, hardware and memory models are consistent across platforms.
The bigger polemic in languages today is probably whether they are statically or dynamically typed, which is to say not how fast will they run, but will the errors be found by the compiler beforehand (at the cost of the programmer having to specify pretty complex typing information) or will the errors come up in testing and production.
您可以使用交互式 Ruby Shell irb 以交互方式运行 Ruby 程序。 虽然它可以生成中间字节码,但它肯定不是传统意义上的“编译器”。
You can run Ruby programs interactively using irb, the Interactive Ruby Shell. While it may generate intermediate bytecode, it's certainly not a "compiler" in the traditional sense.
编译语言通常被编译为机器代码,而不是字节代码。 不过,一些字节码生成器实际上可以进一步将字节码编译为机器代码。
字节码本身只是用户编写的文字代码和虚拟机之间的中间步骤,但它仍然需要由虚拟机解释(就像在 JVM 中使用 Java 和带有操作码缓存的 PHP 完成的那样)。
A compiled language is generally compiled into machine code, as opposed to just byte code. Some byte code generators can actually further compile the byte code into machine code though.
Byte code itself is just an intermediate step between the literal code written by the user and the virtual machine, it still needs to be interpreted by the virtual machine though (as it's done with Java in a JVM and PHP with an opcode cache).
这可能有点偏离主题,但是...
Iron Ruby 是基于 .net 的 ruby 实现,因此通常编译为字节代码,然后在运行时 JIT 编译为机器语言(即不解释)。 另外(至少对于其他.net语言,所以我假设使用ruby) ngen 可用于提前生成已编译的本机二进制文件,因此这实际上是 ruby 代码的机器代码编译版本。
This is possibly a little off topic but...
Iron Ruby is a .net based implementation of ruby and therefore is usually compiled to byte code and then JIT compiled to machine language at runtime (i.e. not interpreted). Also (at least with other .net languages, so I assume with ruby) ngen can be used to generate a compiled native binary ahead of time, so that's effectively a machine code compiled version of ruby code.
至于我从上海 RubyConf 2011 获得的信息,Matz 正在开发一个“MRuby”(代表 Matz 的 Ruby),目标是在嵌入式设备上运行。 Matz 表示,MRuby 将提供将 ruby 代码编译为机器代码的能力,以提高速度并减少嵌入式设备上(有限)资源的使用。 因此,Ruby 实现有多种类型,并且绝对不是所有的实现都只是在运行时解释。
As for the information I got from RubyConf 2011 in Shanghai, Matz is developing a 'MRuby'(stands for Matz's Ruby) to targeting running on embedded devices. And Matz said the the MRuby, will provide the ability to compile the ruby code into machine code to boost the speed and decrease the usage of the (limited) resources on the embedded devices. So, there're various kind of Ruby implementation and definitely not all of them are just interpreted during the runtime.