动态类型的语言是单类型的
比较类型系统,动态类型没有优势。动态类型是静态类型的一种特殊情况 -它是一种静态类型的语言,其中每个变量都具有相同的类型。你可以通过使每个变量是类型的实现在Java中(零下简洁)同样的事情Object
,并具有“对象”值类型Map<String, Object>
:
void makeItBark(Object dog) {
Map<String, Object> dogMap = (Map<String, Object>) dog;
Runnable bark = (Runnable) dogMap.get("bark");
bark.run();
}
因此,即使没有反射,您也几乎可以在任何静态类型的语言中实现相同的效果,并且不使用语法上的便利。您没有任何其他表达能力;相反,你有更少的表达能力,因为在一个动态类型语言,你否认限制变量对某些类型的能力。
用静态类型的语言制作鸭皮
而且,一种好的静态类型语言将允许您编写与任何具有bark
操作的类型一起使用的代码。在Haskell中,这是一个类型类:
class Barkable a where
bark :: a -> unit
这表达了这样的约束:对于某些类型a
被认为是Barkable,必须存在一个bark
函数,该函数采用该类型的值并且不返回任何值。
然后,您可以根据Barkable
约束条件编写通用函数:
makeItBark :: Barkable a => a -> unit
makeItBark barker = bark (barker)
这表示makeItBark
它将满足任何类型Barkable
的要求。这似乎类似于interface
在Java或C#,但它有一个很大的优势-类型没有指定了前面,他们满足哪种类型的类。我可以说这种类型Duck
是Barkable
任何时候,即使Duck
是我没有写过的第三方类型。实际上,作者Duck
没有编写bark
函数也没关系-当我告诉Duck
满足条件的语言时,我可以在事后提供它Barkable
:
instance Barkable Duck where
bark d = quack (punch (d))
makeItBark (aDuck)
这表示Duck
s可以吠叫,而它们的吠叫功能是通过在鸭子发出嘎嘎声之前先对其进行打孔来实现的。这样一来,我们就可以呼吁makeItBark
鸭子了。
Standard ML
并且OCaml
更加灵活,因为您可以通过多种方式满足同一个类型类。在这些语言中,我可以说可以使用常规排序对整数进行排序,然后转而说它们也可以按除数进行排序(例如,10 > 5
因为10可被5整除)。在Haskell中,您只能实例化一次类型类。(这使Haskell可以自动知道可以调用bark
鸭子了;在SML或OCaml中,您必须明确要使用哪个 bark
函数,因为可能有多个。)
简明
当然,在语法上存在差异。您提供的Python代码比我编写的Java代码简明得多。实际上,简洁是动态类型语言魅力的重要组成部分。但是通过类型推断,您不必显式地编写每个变量的类型,从而使您可以编写与静态类型的语言一样简洁的代码。静态类型的语言还可以为动态类型提供本机支持,从而消除了所有强制类型转换和映射操作(例如C#dynamic
)的冗长性。
正确但类型错误的程序
公平地说,即使类型检查器无法验证,静态类型也必须排除某些技术上正确的程序。例如:
if this_variable_is_always_true:
return "some string"
else:
return 6
if
即使else分支永远不会发生,大多数静态类型的语言也会拒绝该语句。在实践中,似乎没有人使用这种类型的代码-对于类型检查器来说,任何太聪明的事情都可能使您的代码的未来维护者诅咒您和您的近亲。举例来说,有人成功地将4个开源Python项目转换为Haskell,这意味着他们没有做任何好的静态类型语言无法编译的事情。而且,编译器发现了一些与类型相关的错误,而单元测试没有发现这些错误。
我看到的关于动态类型的最强论据是Lisp的宏,因为它们允许您任意扩展语言的语法。但是,类型化拍子是具有宏的Lisp的静态类型化方言,因此似乎静态类型化和宏并不是互斥的,尽管可能很难同时实现。
苹果和橙子
最后,不要忘了语言之间的差异不仅限于类型系统。在Java 8之前,实际上不可能用Java 进行任何类型的功能编程。一个简单的lambda将需要4行样板匿名类代码。Java也不支持集合文字(例如[1, 2, 3]
)。工具(IDE,调试器),库和社区支持的质量和可用性也可能存在差异。当某人声称在Python或Ruby中比Java更有生产力时,需要考虑该功能差异。比较包含所有电池,语言核心和类型系统的语言是有区别的。
makeItBark(collections.namedtuple("Dog", "bark")(lambda x: "woof woof"))
。该参数甚至都不是类,而是一个名为tuple的匿名名称。鸭子输入(“如果它发出嘎嘎声……”)使您可以进行具有零限制且无语法开销的临时接口。您可以使用Java之类的语言来执行此操作,但最终会产生很多混乱。如果Java中的函数需要ArrayList,而您想给它另一个收集类型,那么您就是SOL。在python中甚至无法出现。