这要求由阿莱克斯布罗姆菲尔德指出:
几乎所有带有静态类型系统的语言都具有动态类型系统。除了C,我想不到一个例外
这是有效的主张吗?我知道在运行时使用反射或加载类,Java会有点像这样-但是,这种“渐进式输入”的思想可以扩展到多种语言吗?
这要求由阿莱克斯布罗姆菲尔德指出:
几乎所有带有静态类型系统的语言都具有动态类型系统。除了C,我想不到一个例外
这是有效的主张吗?我知道在运行时使用反射或加载类,Java会有点像这样-但是,这种“渐进式输入”的思想可以扩展到多种语言吗?
Answers:
原始高音扬声器在这里。:)
首先,我对自己的推文被如此认真地感到很开心/震惊!如果我知道它将被广泛传播,那么我将花费超过30秒钟来编写它!
Thiago Silva是正确的指出,“静态”和“动态”更准确地描述了类型检查,而不是类型系统。实际上,说一种语言是静态还是动态类型也不是很准确。而是,一种语言具有类型系统,并且该语言的实现可能会使用静态检查或动态检查,或同时使用这两种方法或两者都不执行(尽管这不是非常吸引人的语言实现!)来强制执行类型系统。
碰巧的是,某些类型系统(或类型系统的特征)更适合于静态检查,并且某些类型系统(或类型系统的特征)更适合于动态检查。例如,如果您的语言允许您在程序的文本中指定特定值必须始终是整数数组,那么编写静态检查器以验证该属性相当合理。相反,如果您的语言具有子类型,并且允许向下转换,则在运行时检查向下转换的有效性相当简单,但在编译时则非常困难。
我真的被我的鸣叫的意思很简单,就是绝大多数语言实现的执行一些动态类型检查的数量。或者,等效地,绝大多数语言都具有一些难以(如果不是不可能)进行静态检查的功能。向下转换就是一个例子。其他示例包括算术溢出,数组边界检查和null检查。其中有些可以在某些情况下进行静态检查,但是总的来说,您很难找到在运行时不进行任何检查的语言实现。
这不是一件坏事。只是观察到,我们希望我们的语言强制执行许多有趣的属性,而我们实际上并不知道如何进行静态检查。提醒您,“静态类型”与“动态类型”之类的区别并不像某些人所希望的那样清晰。:)
最后一点:编程语言研究社区中并未真正使用术语“强”和“弱”,并且它们的含义并不一致。总的来说,我发现当有人说某种语言具有“强类型”而另一种语言具有“弱类型”时,他们实际上是在说自己喜欢的语言(具有“强类型”的一种)会阻止他们犯了一个错误,即另一种语言(“弱类型”的一种)不会-或者相反,他们最喜欢的语言(“弱类型”的一种)使他们做一些很酷的事情,而另一种语言(带有“强类型”的关键字)。
嗯,是。您可以使用任何静态类型的语言来放置财产袋。语法将很糟糕,同时您将获得动态类型系统的所有缺点。因此,除非编译器允许您使用更好的语法(如C#dynamic
所做的事情),否则实际上并没有任何优势。
同样,您也可以在C中轻松完成该操作。
对其他答案的反应:我认为人们将静态/动态输入与强/弱输入相混淆。动态类型化是关于能够在运行时更改数据的结构,以及使代码能够使用恰好符合代码需求的数据。这就是所谓的Duck Typing。
提及反射并不能说明全部问题,因为反射不允许您更改数据的现有结构。您不能使用C,C ++,Java或C#将新字段添加到类或结构中。在动态语言中,不仅可以向现有类添加新的字段或属性,而且实际上很常见。
例如,查看Cython,这是Python到C的编译器。它创建静态C代码,但类型系统仍保留其动态特性。C是静态类型的语言,但它能够支持来自Python的动态类型。
ExpandoObject
,从版本4开始使用C#,尽管它是一个选择性的过程,与JavaScript或Ruby截然不同。不过,您已经提出了非常重要的一点,那就是鸭子输入(99%的开发人员在说“动态类型”时实际上意味着什么)和反射根本不是一回事。
True
,以说“这个疯狂的对象是我正在定义的类的实例”)。据我了解,OCaml确实具有此功能,但我真的不知道。
动态语言是静态语言。通常所谓的“动态类型”实际上是静态类型的一种特殊情况-这种情况是您将自己限制为仅具有一种类型。作为一个思想实验,想象一下Object
在调用任何方法之前,仅使用变量/字段/参数编写Java或C#程序,并向下转换。将像Python或Javascript这样的语言称为“ unityped”会更准确。(这种说法可能会使许多人感到困惑/烦恼,考虑到这样的Java或C#程序将使用许多子类型,但这是因为普通的OOP语言会压缩类型和类。有关更多详细信息,请参阅博客文章。)
请注意,即使C也具有“动态”类型-您可以将任何指针转换为void
(如果有内存,则可以char
)指针,然后再次返回。还要注意,那里没有运行时检查。如果您弄错了,请享受您未定义的行为!
String foo = (String) bar
并不意味着bar
实际上是一个String
。您只能在运行时肯定知道这一点,所以我看不到投射是如何“静态”完成的。
dynamic
对象来执行此操作。如果您尝试向...添加属性object
,那您就不能。
静态和动态类型之间的差别是当一个值的类型检查:编译时间与运行时间。在值带有类型的语言(例如Java对象)中,即使语言实际上更喜欢静态类型,您也可以始终诉诸于动态类型。这是Java中带有动态类型化方法的示例:
void horribleJava(List untypedList) {
for (Object o : untypedList)
((SpecificType) o).frobnicate();
}
注意如何在运行时检查每个项目的类型。等效的静态类型方法为:
void goodJava(List<SpecificType> typedList) {
for (SpecificType o : typedList) {
o.forbnicate();
}
}
在C语言中,值(尤其是指针)在运行时不会保留其类型-每个指针都等效于a void *
。相反,变量和表达式具有类型。为了实现动态类型,您必须自己携带类型信息(例如,作为结构中的字段)。
frobnicate
在不了解的情况下,您无法在此处调用该方法SpecificType
。
dynamic
关键字)。将静态等同于编译时,将动态等同于运行时几乎只会使事情变得混乱。
[1,2].Add([3,4])
产生[1,2,3,4]
,[1,2,[3,4]]
或[4,6]
?
Add
array上没有任何方法可以接受数组,因为这样的方法会模棱两可。鸭子打字不会使您无法理解各种类型和功能。
静态类型与动态类型基本上是指如何检查类型。静态类型表示基于实际代码(通常由编译器)检查各种变量或表达式类型的验证,而在动态类型系统中,此验证仅在运行时由运行时环境执行。
我认为本文所指的是,即使实际上是静态检查类型,也要在运行时(即动态检查)类型。您正确地提到了Java Reflection;反射仅在运行时发生,而Java运行时环境(JVM)实际上在使用反射时执行类型检查,这基本上意味着动态类型检查。