编译语言不具备哪些解释语言特有的特性?

7
解释性语言通常更高级,因此具有动态类型(包括在没有声明的情况下动态创建新变量)、臭名昭著的 eval 和许多其他功能,使程序员的生活更轻松。但为什么编译语言不能也拥有这些功能呢?我指的不是像 Java 这样在虚拟机上运行的语言,而是像 C(++)这样编译成二进制文件的语言。我现在不打算列出清单,但如果你想知道我指的哪些功能,请查看 PHP、Python、Ruby 等语言提供的内容。
常见的解释性语言特性有哪些不能存在于编译语言中?为什么?

这应该是社区维基,因为它没有明确的答案(我甚至不确定它是否会被关闭)。请按“编辑”并选中“Communit Wiki”框。 - R. Martinho Fernandes
此外,我认为在这个讨论中Java和C ++之间的区别毫无意义。 - R. Martinho Fernandes
请查看https://dev59.com/VXI95IYBdhLWcg3wzRTv以获取一些类似的想法! - Dario
4
答案是没有。编译器实现可以做任何解释器实现可以做的事情。 - David Thornley
5个回答

4
无论源代码是编译成本地二进制文件、某种中间语言(Java Bytecode/IL),还是解释执行,这绝对不是语言的特性。这只是实现方式的问题。
实际上,您可以为同一种语言同时拥有编译器和解释器,例如:
- Haskell: GHC <-> GHCI - C: gcc <-> ch - VB6: VS IDE <-> VB6 compiler 某些语言功能(如 eval 或动态类型)可能暗示了所谓的“动态语言”和静态语言之间的区别,但运行方式永远不可能是主要问题。

当您运行编译后的Java时,实际上是在解释Java字节码。除了Ruby可读性强而Java字节码不可读之外,我并没有看到很多区别。这并不重要。如果您仔细思考一下,我们可以忽略“人为”的编译和解释之间的区别,使问题无关紧要,并转而考虑动态/静态划分。 - R. Martinho Fernandes
@Martinho:没错。甚至可以称带有源代码的独立解释器为编译器 ;) - Dario
我想知道是否有可能创建一种编程语言,使其无法编译。 - Anderson Green
此外,在底层,机器码只是由处理器解释执行。 - dader

0

最初,解释型语言的最大好处之一是调试。这样,当寻找程序不工作的原因时,您可以获得非常准确和详细的信息。然而,现在大多数编译器已经变得足够先进,这已经不再是一个大问题了。

另一个主要优点(在我看来),是使用解释型语言,您不必等待漫长的时间来编译项目以进行测试。


4
未解答问题。 - anon

0

你不能合理地使用eval,例如,出于我认为非常明显的原因:你会如何实现它?难道让运行时包含编译器的完整副本吗?每次想要评估一个字符串(记住每次可能都不同!),你都需要将该字符串保存到文件中,运行编译器以制作DLL/shared-lib,然后加载该DLL/shared-lib并调用你的代码?你看不出这可能有点不切实际吗?;)

在动态语言中,你可以在很多地方找到这种类型的东西,而在静态代码中,除了在幕后基本上运行解释器之外,你无法做到。


1
我认为你可以使用eval。而且你已经说过如何做了:让运行时包含编译器的完整副本。这就是解释型语言的做法,不是吗?调用eval无非就是调用解释器。所以,在编译型语言中,它应该无非就是调用编译器。在.NET中,你可以直接发出IL代码(一些汇编/字节码),而无需“将字符串保存到文件中,...加载DLL”。这并不是那么罕见的。尽管没有多少人像“eval”那样使用某种东西,但这并不是那么不切实际。 - R. Martinho Fernandes
一个现实世界的例子:boo被编译并有一个解释器。我认为在解释器的深处有一个eval。还有,Dario说的话也是这样。 - R. Martinho Fernandes
1
我看过C#的REPL行为演示。因此,编译语言也可以进行eval操作。 - John Fisher
@John Fisher:那可能是Anders Hejlsberg在PDC'08(http://channel9.msdn.com/pdc2008/TL16/)上的演示。当时他正在使用C#“超越4.0”的语言原型。 - R. Martinho Fernandes
现实世界的例子:Common Lisp。良好的实现是编译的。 - David Thornley
显示剩余4条评论

0

接着Dario的话题,我认为你真正想问的是为什么编译程序不能在运行时评估语句(例如eval)。以下是我能想到的一些原因:

  • 完整的编译器必须与程序一起分发(或成为程序的一部分)
  • 为了使eval函数能够访问环境中的类型信息和符号(例如变量名和函数名),原始程序必须编译为可访问这些符号(编译语言通常会在编译时删除这些符号)。

编辑:如上所述,这两个原因都不会使语言/编译器无法在运行时评估代码,但它们绝对是在开发编译器或设计语言时需要考虑的事情。


1
Common Lisp在运行时具有“eval”,并且具有工业级实现是编译的。 - David Thornley
我不是在说编译程序不可能有一个 eval,我只是提供了一些原因,解释为什么很多语言没有 eval。我会更新我的答案,以使这一点更清楚。 - CiscoIPPhone
编译器可以与运行时一起分发,就像解释器不是解释程序的一部分一样。此外,现代平台(如.NET和Java)在编译单元的元数据中携带类型信息(.NET中的程序集,Java中的JAR)。仅剥离局部变量名,因为即使是局部变量本身也可以通过优化完全删除。 - R. Martinho Fernandes
关于eval,请参阅https://dev59.com/qUvSa4cB1Zd3GeqPivhL#2261718:可能会很有趣。 - Dario

0
也许问题并不是关于解释型/编译型语言(编译本身就很模糊),而是关于那些带/不带自己编译器的语言?例如,我们已经说过C++可以通过应用程序中方便的编译器进行eval操作,反射在某些方面可能类似。

有一些专门为此目的设计的C编译器库,可以将C编译器嵌入到您的应用程序中,以便使用C进行脚本编写。libtcc就是其中之一的例子。 - Jörg W Mittag

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接