与静态类型语言相比,动态类型语言的优点和局限性是什么?
另见:动态语言的爱是什么(一个更具争议性的话题…)
与静态类型语言相比,动态类型语言的优点和局限性是什么?
另见:动态语言的爱是什么(一个更具争议性的话题…)
解释器推断类型和类型转换的能力使开发时间更快,但它也可能引发运行时失败,这是在静态类型语言中无法得到的,因为在编译时就可以捕捉到。但是哪一个更好(或者即使这是真的)最近在社区里被热议(而且已经持续了很长一段时间)。
关于这个问题,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.
摘自Artima的《Typing: Strong vs. Weak, Static vs. Dynamic》文章:
强类型可以防止在不匹配的类型之间混合操作。为了混合类型,必须使用显式转换 弱类型意味着可以在没有显式转换的情况下混合类型
在Pascal Costanza的论文《动态与静态类型——基于模式的分析》(PDF)中,他声称在某些情况下,静态类型比动态类型更容易出错。一些静态类型语言强迫你手动模拟动态类型,以便做“正确的事情”。Lambda the Ultimate讨论过这个问题。
关于静态语言和动态语言有很多不同的东西。对我来说,主要的区别是在动态语言中,变量没有固定的类型;相反,类型被绑定到值。因此,要执行的确切代码直到运行时才确定。
在早期或naïve实现中,这是一个巨大的性能拖累,但现代jit已经非常接近优化静态编译器的最佳性能。(在一些边缘情况下,甚至比这更好)。
静态类型系统寻求静态地消除某些错误,在不运行程序的情况下检查程序,并试图证明在某些方面的合理性。一些类型系统能够捕获比其他类型更多的错误。例如,如果使用得当,c#可以消除空指针异常,而Java没有这种能力。Twelf有一个类型系统,它实际上保证证明将终止,“解决”停止问题。
However, no type system is perfect. In order to eliminate a particular class of errors, they must also reject certain perfectly valid programs which violate the rules. This is why Twelf doesn't really solve the halting problem, it just avoids it by throwing out a large number of perfectly valid proofs which happen to terminate in odd ways. Likewise, Java's type system rejects Clojure's PersistentVector implementation due to its use of heterogeneous arrays. It works at runtime, but the type system cannot verify it.
因此,大多数类型系统都提供了“转义”,即覆盖静态检查器的方法。对于大多数语言来说,它们采取强制转换的形式,尽管有些语言(如c#和Haskell)有完整的模式被标记为“不安全”。
Subjectively, I like static typing. Implemented properly (hint: not Java), a static type system can be a huge help in weeding out errors before they crash the production system. Dynamically typed languages tend to require more unit testing, which is tedious at the best of times. Also, statically typed languages can have certain features which are either impossible or unsafe in dynamic type systems (implicit conversions spring to mind). It's all a question of requirements and subjective taste. I would no more build the next Eclipse in Ruby than I would attempt to write a backup script in Assembly or patch a kernel using Java.
哦,那些说“打x字比打y字效率高10倍”的人简直是在吹牛。在许多情况下,动态类型可能“感觉”更快,但一旦您真正尝试运行您的花哨应用程序,它就失去了优势。同样地,静态类型可能看起来是完美的安全网,但只要看一下Java中一些更复杂的泛型类型定义,大多数开发人员就会匆忙寻找令人眼花缭乱的东西。即使有类型系统和生产力,也没有什么灵丹妙药。
最后注意:在比较静态类型和动态类型时,不要担心性能。像V8和TraceMonkey这样的现代jit正在危险地接近静态语言性能。此外,Java实际上被编译为一种固有的动态中间语言,这一事实应该表明,在大多数情况下,动态类型并不是一些人认为的巨大性能杀手。
关键是要有合适的工具。这两种方法都不是100%的好方法。这两种制度都是人为创造的,都有缺陷。抱歉,我们做的东西太烂了。
我喜欢动态类型,因为它让我摆脱了我的方式,但是是的,运行时错误可能会出现,这是我没有计划到的。 静态类型可能会修复前面提到的错误,但会让新手(在类型化语言中)程序员疯狂地尝试在常量字符和字符串之间进行强制转换。
It depends on context. There a lot benefits that are appropriate to dynamic typed system as well as for strong typed. I'm of opinion that the flow of dynamic types language is faster. The dynamic languages are not constrained with class attributes and compiler thinking of what is going on in code. You have some kinda freedom. Furthermore, the dynamic language usually is more expressive and result in less code which is good. Despite of this, it's more error prone which is also questionable and depends more on unit test covering. It's easy prototype with dynamic lang but maintenance may become nightmare.
相对于静态类型系统的主要优点是IDE支持和静态代码分析器。 在每次代码更改之后,您都会对代码更加自信。用这样的工具来维护蛋糕是和平的。
Perhaps the single biggest "benefit" of dynamic typing is the shallower learning curve. There is no type system to learn and no non-trivial syntax for corner cases such as type constraints. That makes dynamic typing accessible to a lot more people and feasible for many people for whom sophisticated static type systems are out of reach. Consequently, dynamic typing has caught on in the contexts of education (e.g. Scheme/Python at MIT) and domain-specific languages for non-programmers (e.g. Mathematica). Dynamic languages have also caught on in niches where they have little or no competition (e.g. Javascript).
最简洁的动态类型语言(例如Perl, APL, J, K, Mathematica)是特定于领域的,并且在它们设计的利基领域中比最简洁的通用静态类型语言(例如OCaml)要简洁得多。
动态类型的主要缺点是:
运行时类型错误。 要达到相同水平的正确性是非常困难的,甚至实际上是不可能的,并且需要大量的测试。 没有经过编译器验证的文档。 糟糕的性能(通常在运行时,但有时在编译时,例如斯大林方案)和由于依赖复杂的优化而不可预测的性能。
就我个人而言,我是伴随着动态语言长大的,但作为一名专业人士,除非没有其他可行的选择,否则不会用40英尺的杆子接触它们。
这两者都被误解得非常非常非常严重,而且是完全不同的两件事。它们不是相互排斥的。
Static types are a restriction of the grammar of the language. Statically typed languages strictly could be said to not be context free. The simple truth is that it becomes inconvenient to express a language sanely in context free grammars that doesn't treat all its data simply as bit vectors. Static type systems are part of the grammar of the language if any, they simply restrict it more than a context free grammar could, grammatical checks thus happen in two passes over the source really. Static types correspond to the mathematical notion of type theory, type theory in mathematics simply restricts the legality of some expressions. Like, I can't say 3 + [4,7] in maths, this is because of the type theory of it.
Static types are thus not a way to 'prevent errors' from a theoretical perspective, they are a limitation of the grammar. Indeed, provided that +, 3 and intervals have the usual set theoretical definitions, if we remove the type system 3 + [4,7]has a pretty well defined result that's a set. 'runtime type errors' theoretically do not exist, the type system's practical use is to prevent operations that to human beings would make no sense. Operations are still just the shifting and manipulation of bits of course.
这样做的问题在于,类型系统无法决定是否将发生这样的操作(如果允许它运行)。也就是说,准确地将所有可能的程序集划分为那些将会有“类型错误”的程序和那些没有“类型错误”的程序。它只能做两件事:
1:证明程序中会出现类型错误 2:证明它们不会出现在程序中
This might seem like I'm contradicting myself. But what a C or Java type checker does is it rejects a program as 'ungrammatical', or as it calls it 'type error' if it can't succeed at 2. It can't prove they aren't going to occur, that doesn't mean that they aren't going to occur, it just means it can't prove it. It might very well be that a program which will not have a type error is rejected simply because it can't be proven by the compiler. A simple example being if(1) a = 3; else a = "string";, surely since it's always true, the else-branch will never be executed in the program, and no type error shall occur. But it can't prove these cases in a general way, so it's rejected. This is the major weakness of a lot of statically typed languages, in protecting you against yourself, you're necessarily also protected in cases you don't need it.
但是,与流行的观点相反,还有一些静态类型语言是根据原则1工作的。他们只是拒绝所有他们能证明会导致类型错误的程序,并通过所有他们不能证明会导致类型错误的程序。所以有可能它们允许程序中有类型错误,一个很好的例子是类型化球拍,它是动态和静态类型的混合。有些人会说,在这个系统中,你得到了两全其美的东西。
静态类型的另一个优点是类型在编译时已知,因此编译器可以使用它。如果我们在Java中使用“string”+“string”或“3 + 3”,文本中的两个+标记最终都代表了完全不同的操作和数据,编译器只知道从类型中选择哪个。
现在,我要在这里做一个非常有争议的陈述,但请容忍我:“动态类型”并不存在。
听起来很有争议,但这是事实,动态类型语言从理论的角度来看是无类型的。它们只是只有一种类型的静态类型语言。或者简单地说,它们确实是在实践中由上下文无关的语法生成的语言。
Why don't they have types? Because every operation is defined and allowed on every operant, what's a 'runtime type error' exactly? It's from a theoretical example purely a side-effect. If doing print("string") which prints a string is an operation, then so is length(3), the former has the side effect of writing string to the standard output, the latter simply error: function 'length' expects array as argument., that's it. There is from a theoretical perspective no such thing as a dynamically typed language. They are untyped
好吧,“动态类型”语言的明显优势是表达能力,类型系统只不过是表达能力的限制。一般来说,带有类型系统的语言确实会为所有不允许的操作定义一个结果,如果忽略类型系统,结果对人类来说就没有意义了。许多语言在应用类型系统后失去了图灵完整性。
The obvious disadvantage is the fact that operations can occur which would produce results which are nonsensical to humans. To guard against this, dynamically typed languages typically redefine those operations, rather than producing that nonsensical result they redefine it to having the side effect of writing out an error, and possibly halting the program altogether. This is not an 'error' at all, in fact, the language specification usually implies this, this is as much behaviour of the language as printing a string from a theoretical perspective. Type systems thus force the programmer to reason about the flow of the code to make sure that this doesn't happen. Or indeed, reason so that it does happen can also be handy in some points for debugging, showing that it's not an 'error' at all but a well defined property of the language. In effect, the single remnant of 'dynamic typing' that most languages have is guarding against a division by zero. This is what dynamic typing is, there are no types, there are no more types than that zero is a different type than all the other numbers. What people call a 'type' is just another property of a datum, like the length of an array, or the first character of a string. And many dynamically typed languages also allow you to write out things like "error: the first character of this string should be a 'z'".
Another thing is that dynamically typed languages have the type available at runtime and usually can check it and deal with it and decide from it. Of course, in theory it's no different than accessing the first char of an array and seeing what it is. In fact, you can make your own dynamic C, just use only one type like long long int and use the first 8 bits of it to store your 'type' in and write functions accordingly that check for it and perform float or integer addition. You have a statically typed language with one type, or a dynamic language.
In practise this all shows, statically typed languages are generally used in the context of writing commercial software, whereas dynamically typed languages tend to be used in the context of solving some problems and automating some tasks. Writing code in statically typed languages simply takes long and is cumbersome because you can't do things which you know are going to turn out okay but the type system still protects you against yourself for errors you don't make. Many coders don't even realize that they do this because it's in their system but when you code in static languages, you often work around the fact that the type system won't let you do things that can't go wrong, because it can't prove it won't go wrong.
正如我所指出的,“静态类型”通常意味着情况2,在被证明无罪之前是有罪的。但是,有些语言根本不是从类型理论中派生出类型系统的,它们使用规则1:在被证明有罪之前是无辜的,这可能是理想的混合。所以,也许打字球拍适合你。
还有一个更荒谬和极端的例子,我目前正在实现一种语言,其中'类型'是数组的第一个字符,它们是数据,'类型'的数据,'类型'本身就是一个类型和数据,唯一的数据本身就是一个类型。类型不是静态的有限或有界的,但是可以根据运行时信息生成新类型。
静态类型: Java和Scala等语言是静态类型的。
在代码中使用变量之前,必须对变量进行定义和初始化。
前女友。 int x; X = 10;
System.out.println (x);
动态类型: Perl是一种动态类型语言。
变量在代码中使用之前不需要初始化。
y = 10;在后面的代码中使用这个变量