为什么动态打字经常与口译语言相关联?

时间:2009-09-08 13:00:36

标签: language-design type-systems typing dynamic-typing static-typing

简单的问题人员:我在编译语言(如C ++ / Java)和Python / Javascript等解释语言中进行了大量编程(专业和个人)。我个人发现,当我使用静态类型语言编程时,我的代码几乎总是更强大。但是,我遇到的几乎所有解释语言都使用动态类型(PHP,Perl,Python等)。我知道为什么编译语言使用静态类型(大多数时候),但我无法弄清楚解释语言设计中对静态类型的厌恶。

为什么陡峭断开?它是解释语言性质的一部分吗? OOP?

7 个答案:

答案 0 :(得分:48)

有趣的问题。顺便说一下,我是phc(PHP的编译器)的作者/维护者,我正在为动态语言编译器学习博士学位,所以我希望我能提供一些见解。

我认为这里有一个错误的假设。 PHP,Perl,Python,Ruby,Lua等的作者没有设计“解释语言”,他们设计了动态语言,并使用解释器实现了它们。他们这样做是因为解释器比编译器更容易编写。

Java的第一个实现被解释,它是一种静态类型语言。对于静态语言存在解释器:Haskell和OCaml都有解释器,并且过去常常是C的流行解释器,但这是很久以前的事了。它们很受欢迎,因为它们允许REPL,这可以使开发更容易。

也就是说,正如您所期望的那样,动态语言社区中存在对静态类型的厌恶。他们认为C,C ++和Java提供的静态类型系统是冗长的,不值得努力。我认为我在一定程度上同意这一点。使用Python编程比C ++更有趣。

解决其他问题:

  • dlamblin says:“我从来没有强烈地认为编译与解释有任何特殊之处,这表明动态过于静态打字。”嗯,那里你错了。动态语言的编译非常困难。主要有eval语句要考虑,它在Javascript和Ruby中广泛使用。 phc提前编译PHP,但我们仍然需要一个运行时解释器来处理evaleval也无法在优化编译器中进行静态分析,但如果您不需要健全,则cool technique会有。{/ p>

  • damblin对Andrew Hare的回复:你当然可以在解释器中执行静态分析,并在运行时之前找到错误,这正是Haskell的{{1确实。我希望函数式语言中使用的解释器风格需要这样。 dlamblin当然可以说分析不是解释的一部分。

  • Andrew Hare's answer是基于提问者错误的假设,同样也有错误的方法。然而,他提出了一个有趣的问题:“动态语言的静态分析有多难?”。非常非常努力。基本上,你将获得一个博士学位来描述它是如何工作的,这正是我正在做的事情。另见前一点。

  • 到目前为止,最正确的答案是Ivo Wetzel。但是,他描述的要点可以在编译器中的运行时处理,并且Lisp和Scheme存在许多具有这种动态绑定的编译器。但是,是的,它很棘手。

答案 1 :(得分:4)

解释语言使用动态类型,因为没有编译步骤可以进行静态分析。编译语言在编译时进行静态分析 ,这意味着任何类型的错误都会在开发人员工作时报告。

如果您认为静态类型语言具有在执行上下文之外强制执行类型规则的编译器,则更容易理解。解释语言永远不会被静态分析,因此类型规则必须由执行环境中的解释器强制执行。

答案 2 :(得分:4)

我认为这是因为解释语言的本质,他们希望是动态的,所以你可以在运行时改变一些东西。由于这个原因,编译器在下一行代码被激活之后永远不知道程序的状态是什么。

想象一下以下场景(在Python中):

import random
foo = 1

def doSomeStuffWithFoo():
    global foo
    foo = random.randint(0, 1)

def asign():
    global foo
    if foo == 1:
        return 20
    else:
        return "Test"


def toBeStaticallyAnalyzed():
    myValue = asign()

    # A "Compiler" may throw an error here because foo == 0, but at runtime foo maybe 1, so the compiler would be wrong with its assumption
    myValue += 20


doSomeStuffWithFoo() # Foo could be 1 or 0 now... or 4 ;)
toBeStaticallyAnalyzed()

正如您所希望的那样,编译器在这种情况下没有任何意义。它可能会警告你“myValue”可能不是一个数字。 但是在JavaScript中会失败,因为如果“myValue”是一个String,那么20也会被隐含地转换为String,因此不会发生错误。因此,您可能会在整个地方收到成千上万的无用警告,我认为这不是编译器的意图。

灵活性始终需要付出代价,您需要深入了解您的计划,或者更仔细地编程,换句话说,在上述情况下您就是编译器。

所以你的解决方案作为编译器? - 使用“try:except”修复它:)

答案 3 :(得分:2)

编译器+静态类型=高效的机器代码
编译器+动态类型=低效的机器代码

考虑以下伪代码:

function foo(a, b) {
    return a+b
}

静态语言将能够(通过声明或推断)知道a和b是整数,并将编译为

%reg = addi a,b
无论如何,

或类似的东西。

动态语言的编译器必须将代码发送到
1.检查a和b的类型 2.处理每个案件或案件组合

%reg1 = typeof a
beq %reg1, int, a_int_case
beq %reg1, float, a_float_case
beq %reg1, string, a_string_case

label a_int_case
%reg1 = typeof b
beq %reg1, int, a_int_b_int_case
beq %reg1, float, a_int_b_float_case
beq %reg1, string, a_int_b_string_case

label a_int_b_int_case
%out = addi a,b
goto done

label a_int_b_float_case
%tmp = mkfloat a
%out = addf %tmp,b
goto done

... Etc. I can't finish

虽然您可以生成比这更智能的机器代码,但您无法帮助生成大量代码 - 这使得编译不是动态语言的主要胜利。

由于解释器更容易编写,编译对你没有多大好处,为什么不写一个解释器呢?

(即时编译器实际上有类型信息,可以编译到单个语句。它们实际上比静态类型系统有更多的信息,理论上可以做得更好。所有汇编程序都是模拟的;任何相似之处可以在真机上运行的真实代码纯属巧合。)

答案 4 :(得分:1)

也许是因为我的主要解释语言之一是Perl而我的编译语言之一是Objective-C,但我从来没有强烈地认为编译与解释有任何特殊之处,建议动态而不是静态类型。

我认为很明显,双方都在关注对方,并在思考,“这有一些优势。”在多个应用程序中,获得一些动态类型的灵活性更容易,同时可以更容易地维护静态类型和强制执行的内容。

我不同意Andrew Hare's explanation。虽然纯粹解释的语言必须在预处理步骤中添加,因此不能纯粹解释为了在执行静态类型错误之前警告程序员,但它并不排除在运行时抛出类型错误。因此缺乏编译并不意味着不会发生静态类型检查。但是,由于在运行时获取类型错误并不像在编译时获得一个错误或在预检检查中那样有用,我可以看到静态类型在这种情况下的“优势”似乎更令人讨厌,因而被抛弃,有利于动态打字带来的好处。

如果你从一开始就知道你喜欢保持你的类型是静态的,因为你亲自编写了更好的可维护代码,并且你正在设计你的解释语言,没有什么能阻止你将这种语言设计为静态类型的语言

引用interpreted languages wiki article“从理论上说,任何语言都可以编译或解释,所以这个名称纯粹是因为共同的实现实践而不是语言的某些基本属性。” 只是在输入时有一个不错的wiki article

答案 5 :(得分:0)

动态类型的解释语言为您提供了更多编程方式的自由。它允许元编程可行。它允许在运行时创建变量。允许在运行时的任何给定时间创建匿名哈希和匿名数组,而无需事先声明任何内容。它允许将未确定的信息输入到散列中,而无需事先声明所有密钥。您可以从未确定的随机输入创建子例程。您也可以提供可以动态运行的程序代码。解释语言释放了一般限制编程的链。您仅限于使用静态类型语言在源文件中键入的内容。您可以使用动态类型语言以更少的资源完成更多工作。

今天制作的大多数机器人更多地处理解释语言,因为需要在运行时确定信息,并且需要在运行时存储新信息以存储此信息。机器学习基于被解释的信息。我们自己作为人类是解释者,这就是机器人以这种方式设计的原因。未来真的被解释了。当然,您需要静态类型语言来构建解释器,因此静态类型语言永远不会消失,除非将来使用汇编代码构建解释器。如今,大多数口译员都是建立在静态类型的语言之上的。

解释语言在动态环境中表现优异。如果您可以在运行时解释新的代码/信息,那么为什么不呢。如果您真的擅长动态编程,那么您可以创建可以创建变量和哈希的代码,而无需输入任何内容。如果您处理大量数据,则可以大幅减少行数。您可以使用数据转储器打印出所有信息,因为解释型语言通常会在运行时跟踪变量的类型,从而实现这一点。你不能在准系统c ++中这样做。唯一一次c ++和c知道发生了什么是在编译时。除非你自己实施一些东西,否则你自己就可以了。

现在谁想要与源文件捆绑在一起,特别是当你在动态环境中工作时。你所做的一切都限制了你的潜力。一旦你的脖子深入动态解释代码,你回到任何静态类型的语言,你会发现你的代码更难以愚蠢,因为你仍然在思考无限的心态。你的思想需要再次回到被限制在源文件中输入的内容。

编程样式的方式: 静态类型代码产生静态结果。动态类型代码会产生动态或静态结果。

如果你要编程的东西永远不会改变已知的东西,那么静态类型的语言就是很好的。如果您处理动态行为,那么动态类型语言更适合用于这些情况。一切都取决于具体情况。

每种语言都有起伏。只需明智地选择和选择。

答案 6 :(得分:-1)

我认为静态类型使编译器更容易,这是编译语言中存在的主要原因(如果不是唯一的原因)。

对于解释型语言,更容易假设变量没有类型(只有值),因为它们不被认为是必须适合内部数据的放置器,而是标记为浮动在堆上某处的数据。

如果程序员想要的话,他总是断言该变量包含给定类型的值(例如在赋值时)。没有理由将它构建成语言。当然,这与编译语言的控制方式不同。

您可能拥有必须明确声明每个变量类型的语言,但如果不这样做,则更容易做有趣的事情,静态类型需要程序员非常精心设计的复杂泛型类型。

另一方面。你知道任何动态类型的编译(静态,而不是JIT)语言吗?