动态类型语言与静态类型语言

Dynamic type languages versus static type languages

与静态类型语言相比,动态类型语言有哪些优点和局限性?

另见:什么与动态语言的爱(一个更具争议性的线程…)


解释器推断类型和类型转换的能力使开发速度更快,但它也会引发运行时故障,在静态类型语言中,您无法在编译时捕获这些故障。但是最近(而且很长一段时间以来)社区里都在热烈讨论哪一个更好(或者即使总是这样)。

解决这个问题的一个好办法是尽可能使用静态类型,必要时使用动态类型:微软的Erik Meijer和Peter Drayton的编程语言之间的冷战结束:

Advocates of static typing argue that
the advantages of static typing
include earlier detection of
programming mistakes (e.g. preventing
adding an integer to a boolean),
better documentation in the form of
type signatures (e.g. incorporating
number and types of arguments when
resolving names), more opportunities
for compiler optimizations (e.g.
replacing virtual calls by direct
calls when the exact type of the
receiver is known statically),
increased runtime efficiency (e.g. not
all values need to carry a dynamic
type), and a better design time
developer experience (e.g. knowing the
type of the receiver, the IDE can
present a drop-down menu of all
applicable members). Static typing
fanatics try to make us believe that
"well-typed programs cannot go wrong".
While this certainly sounds
impressive, it is a rather vacuous
statement. Static type checking is a
compile-time abstraction of the
runtime behavior of your program, and
hence it is necessarily only partially
sound and incomplete. This means that
programs can still go wrong because of
properties that are not tracked by the
type-checker, and that there are
programs that while they cannot go
wrong cannot be type-checked. The
impulse for making static typing less
partial and more complete causes type
systems to become overly complicated
and exotic as witnessed by concepts
such as"phantom types" [11] and
"wobbly types" [10]. This is like
trying to run a marathon with a ball
and chain tied to your leg and
triumphantly shouting that you nearly
made it even though you bailed out
after the first mile.

Advocates of dynamically typed
languages argue that static typing is
too rigid, and that the softness of
dynamically languages makes them
ideally suited for prototyping systems
with changing or unknown requirements,
or that interact with other systems
that change unpredictably (data and
application integration). Of course,
dynamically typed languages are
indispensable for dealing with truly
dynamic program behavior such as
method interception, dynamic loading,
mobile code, runtime reflection, etc.
In the mother of all papers on
scripting [16], John Ousterhout argues
that statically typed systems
programming languages make code less
reusable, more verbose, not more safe,
and less expressive than dynamically
typed scripting languages. This
argument is parroted literally by many
proponents of dynamically typed
scripting languages. We argue that
this is a fallacy and falls into the
same category as arguing that the
essence of declarative programming is
eliminating assignment. Or as John
Hughes says [8], it is a logical
impossibility to make a language more
powerful by omitting features.
Defending the fact that delaying all
type-checking to runtime is a good
thing, is playing ostrich tactics with
the fact that errors should be caught
as early in the development process as
possible.


静态类型系统寻求静态地消除某些错误,在不运行程序的情况下检查程序,并试图在某些方面证明其可靠性。一些类型的系统能够捕获比其他类型更多的错误。例如,当正确使用时,C可以消除空指针异常,而Java没有这样的能力。Twelf有一个类型系统,它实际上保证证明将终止,"解决"停止的问题。

然而,没有一个类型系统是完美的。为了消除特定类型的错误,它们还必须拒绝某些违反规则的完全有效的程序。这就是为什么twelf不能真正解决停顿问题,它只是通过抛出大量恰好以奇怪方式终止的完全有效的证明来避免它。同样,Java的类型系统由于使用异构数组而拒绝了CuljuleEDCX1 0的实现。它在运行时工作,但类型系统无法验证它。

因此,大多数类型系统都提供了"转义"方法来覆盖静态检查器。对于大多数语言,这些语言都采用了强制转换的形式,尽管有些语言(如c和haskell)具有标记为"不安全"的完整模式。

主观上,我喜欢静态类型。正确地执行(提示:不是Java),静态类型系统可以在消除错误之前产生巨大的帮助,从而使生产系统崩溃。动态类型语言往往需要更多的单元测试,这在最好的情况下是乏味的。此外,静态类型语言可以具有某些在动态类型系统中不可能或不安全的特性(隐式转换让人想起)。这都是一个需求和主观品味的问题。我将不再在Ruby中构建下一个Eclipse,而不是尝试在汇编中编写备份脚本或使用Java修补内核。

哦,那些说"x打字比y打字效率高10倍"的人简直是在冒烟。在许多情况下,动态输入可能会"感觉"更快,但一旦您真正尝试让您喜欢的应用程序运行,它就会失去作用。同样,静态类型似乎是完美的安全网,但一看Java中一些更复杂的泛型类型定义,大多数开发人员都会蜂拥而至。即使有了类型系统和生产力,也没有什么好消息。

最后一点注意:在比较静态类型和动态类型时,不要担心性能。像V8和TraceMonkey这样的现代JIT正在危险地接近静态语言性能。此外,Java实际上编译成一种固有的动态中间语言的事实应该是一个暗示,对于大多数情况下,动态类型并不是某些人做出的巨大性能杀手。


好吧,两者都是非常,非常非常误解的,也是两个完全不同的东西。这不是互相排斥的。好的。

静态类型是语言语法的限制。静态类型的语言严格来说不能是上下文无关的。简单的事实是,在上下文无关的语法中理智地表达一种语言会变得不方便,因为这种语法不会将所有数据简单地视为位向量。静态类型系统是语言语法的一部分,如果有的话,它们比上下文无关的语法更简单地限制它,因此语法检查会在源代码的两次传递中发生。静态类型对应于类型论的数学概念,数学中的类型论简单地限制了某些表达式的合法性。比如,我不能在数学中说3 + [4,7],这是因为它的类型理论。好的。

因此,静态类型不是从理论角度"防止错误"的一种方法,它们是语法的一个限制。实际上,如果+3和区间有通常的集合理论定义,那么如果我们去掉类型系统3 + [4,7]有一个定义很好的结果,那就是集合。运行时类型错误理论上不存在,类型系统的实际用途是防止对人类毫无意义的操作。当然,操作仍然只是位的移动和操作。好的。

这一点的关键在于类型系统无法决定是否会发生这样的操作,也无法决定是否允许它运行。如中所述,精确地将所有可能的程序集划分为那些将要发生"类型错误"的程序集和那些将不会发生"类型错误"的程序集。它只能做两件事:好的。

1:证明程序中将发生类型错误2:证明它们不会出现在程序中好的。

这似乎是我在自相矛盾。但是C或Java类型的检查器所做的是拒绝一个程序"不语法",或者它称之为"类型错误",如果它不能在2成功。它不能证明它们不会发生,这并不意味着它们不会发生,只是意味着它不能证明它。很可能一个没有类型错误的程序被拒绝,仅仅是因为它不能被编译器证明。一个简单的例子是if(1) a = 3; else a ="string";,当然,因为它总是正确的,所以else分支永远不会在程序中执行,并且不会发生类型错误。但是它不能以一般的方式证明这些案例,所以它被拒绝了。这是许多静态类型语言的主要弱点,在保护您不受影响的情况下,您也必须受到保护,以防您不需要它。好的。

但是,与人们普遍认为的相反,还有一些静态类型的语言可以根据原则1工作。他们简单地拒绝所有他们能证明会导致类型错误的程序,并通过所有他们不能通过的程序。所以他们有可能允许有类型错误的程序,一个很好的例子是打字,这是动态和静态类型的混合。有些人会争辩说你在这个系统中得到了两个世界中最好的。好的。

静态类型的另一个优点是类型在编译时是已知的,因此编译器可以使用它。如果我们在Java中使用EDCOX1,0,或EDOCX1,1,则EDCOX1,2个文本中的标记代表一个完全不同的操作和数据,编译器知道从类型中选择哪一个。好的。

现在,我将在这里做一个非常有争议的声明,但请记住:"动态类型"不存在。好的。

听起来很有争议,但事实上,动态类型语言从理论上讲是非类型化的。它们只是静态类型的语言,只有一种类型。或者简单地说,它们实际上是由上下文无关语法在实践中生成的语法语言。好的。

为什么他们没有类型?因为每个操作都是在每个操作上定义和允许的,所以什么是"运行时类型错误"?这纯粹是从理论上讲的副作用。如果打印字符串的print("string")是一个操作,那么length(3)也是一个操作,前者有将string写入标准输出的副作用,后者只是error: function 'length' expects array as argument.而已。从理论上讲,没有动态类型语言这样的东西。它们是非类型化的好的。

好吧,"动态类型"语言的明显优点是表达能力,类型系统只是表达能力的限制。一般来说,具有类型系统的语言对于所有那些不允许的操作都会有一个定义的结果,如果类型系统被忽略,结果对人类就没有意义。许多语言在应用类型系统后会失去图灵完整性。好的。

明显的缺点是,操作可能会产生对人类毫无意义的结果。为了防止这种情况发生,动态类型语言通常会重新定义这些操作,而不是产生无意义的结果,它们会将其重新定义为具有写出错误的副作用,并且可能会完全停止程序。这根本不是一个"错误",事实上,语言规范通常意味着这一点,这与从理论角度打印字符串一样是语言的行为。因此,类型系统迫使程序员对代码流进行推理,以确保不会发生这种情况。或者,事实上,这样做的原因在某些调试点上也很方便,这表明它根本不是一个"错误",而是语言的一个定义良好的属性。实际上,大多数语言所拥有的"动态类型"的唯一残余就是防止被零除。这就是动态类型,没有类型,没有类型比零是一个不同的类型比所有其他数字更多的类型。人们所称的"类型"只是数据的另一个属性,比如数组的长度或字符串的第一个字符。许多动态类型语言也允许您写出像"error: the first character of this string should be a 'z'"这样的东西。好的。

另一件事是,动态类型语言在运行时具有可用的类型,通常可以检查并处理它,并从中作出决定。当然,理论上,这与访问数组的第一个字符并查看它是什么没有什么不同。实际上,您可以创建自己的动态C,只需使用long long int这样的一个类型,并使用它的前8位来存储"type",并相应地编写检查它并执行浮点或整数加法的函数。您有一种类型的静态类型语言,或者一种动态语言。好的。

在实践中,这一切都表明,静态类型语言通常用于编写商业软件的上下文中,而动态类型语言往往用于解决某些问题和自动化某些任务的上下文中。用静态类型语言编写代码只需要很长时间,而且很麻烦,因为你不能做你知道会好起来的事情,但是类型系统仍然可以保护你不受错误的影响。许多编码人员甚至没有意识到他们这样做是因为它在他们的系统中,但是当你用静态语言编码时,你经常会遇到这样一个事实:类型系统不会让你做一些不会出错的事情,因为它不能证明它不会出错。好的。

正如我所指出的,"静态类型"通常意味着案例2,在证明无罪之前是有罪的。但是有些语言根本没有从类型理论中派生出它们的类型系统,它们使用规则1:无罪直到被证明有罪,这可能是理想的混合体。所以,也许打出来的球拍是给你的。好的。

另外,好吧,对于一个更为荒谬和极端的例子,我目前正在实现一种语言,其中"类型"实际上是数组的第一个字符,它们是"类型"、"类型"的数据,它本身就是一种类型和数据,唯一的数据本身就是一种类型。类型不是静态的有限或有界的,但可以基于运行时信息生成新类型。好的。好啊。


也许动态打字最大的"好处"就是学习曲线变浅。没有要学习的类型系统,也没有用于角情况(如类型约束)的重要语法。这使得更多的人可以访问动态类型,并且对于许多无法访问复杂静态类型系统的人来说是可行的。因此,动态类型已经在教育(例如麻省理工学院的Scheme/python)和非程序员的领域特定语言(例如Mathematica)中流行起来。动态语言也在那些几乎没有竞争对手或没有竞争对手(如javascript)的细分市场中流行起来。

最简洁的动态类型化语言(例如Perl、Apl、J、K、Mathematica)是特定于领域的语言,可以比它们设计用于的壁龛中最简洁的通用静态类型化语言(例如OCAML)更加简洁。

动态类型的主要缺点是:

  • 运行时类型错误。

  • 可能非常困难,甚至几乎不可能达到相同的正确性水平,并且需要大量的测试。

  • 没有编译器验证的文档。

  • 由于依赖于复杂的优化,性能不佳(通常在运行时,但有时在编译时,例如斯大林方案)和不可预测的性能。

就我个人而言,我是在动态语言的基础上成长起来的,但如果没有其他可行的选择,我就不会以40英尺的职业水准去接触他们。


来自Artima的类型:强与弱,静态与动态文章:

strong typing prevents mixing operations between mismatched types. In order to mix types, you must use an explicit conversion

weak typing means that you can mix types without an explicit conversion

在PascalCostanza的论文《动态与静态打字——基于模式的分析》(PDF)中,他声称在某些情况下,静态打字比动态打字更容易出错。一些静态类型的语言强迫您手动模拟动态类型,以便做"正确的事情"。在lambda终极大会上讨论过。


这取决于上下文。对于动态类型化系统和强类型化系统,有很多好处。我认为动态类型语言的流动更快。动态语言不受类属性和编译器对代码进行思考的约束。你有点自由。此外,动态语言通常更具表现力,导致代码更少,这是好的。尽管如此,它更容易出错,这也是值得怀疑的,并且更多地依赖于单元测试覆盖。这是一个简单的原型与动态语言,但维护可能成为噩梦。

与静态类型系统相比,静态类型系统的主要优点是支持IDE和静态代码分析器。每次代码更改后,您都会对代码更加自信。用这种工具进行维护是轻而易举的。


这一切都是为了工作的正确工具。也不是最好的100%的时间。这两个系统都是人类创造的,都有缺陷。抱歉,但我们很烂,做得很完美。

我喜欢动态打字,因为它挡了我的路,但是的,运行时错误会蔓延到我没有计划的地方。其中,静态类型可以修复前面提到的错误,但会使初学者(使用类型化语言)疯狂地尝试在常量char和字符串之间强制转换。


静态和动态语言有很多不同的地方。对我来说,主要的区别在于,在动态语言中,变量没有固定的类型;相反,类型与值相关。因此,直到运行时才确定执行的确切代码。

在早期还是在NA?ve实现这是一个巨大的性能拖累,但是现代的JIT非常接近优化静态编译器所能达到的最佳水平。(在一些边缘案例中,甚至比这更好)。


静态分型:Java和斯卡拉等语言是静态类型的。

在代码中使用变量之前,必须对其进行定义和初始化。

为Ex.INTX;x=10;

系统.out.println(x);

动态分型:Perl是一种动态类型语言。

变量在代码中使用之前不需要初始化。

y=10;在代码的后面部分使用这个变量