寻求澄清有关弱类型语言的明显矛盾


178

我想我了解强类型,但是每次我寻找弱类型的示例时,我最终都会找到简单地自动强制转换类型的编程语言示例。

例如,在这篇名为“ 打字:强vs.弱”,“静态vs.动态 ”的文章中,Python是强类型的,因为如果尝试执行以下操作,则会得到异常:

蟒蛇

1 + "1"
Traceback (most recent call last):
File "", line 1, in ? 
TypeError: unsupported operand type(s) for +: 'int' and 'str'

但是,在Java和C#中这种事情是可能的,因此我们不认为它们只是弱类型的。

爪哇

  int a = 10;
  String b = "b";
  String result = a + b;
  System.out.println(result);

C#

int a = 10;
string b = "b";
string c = a + b;
Console.WriteLine(c);

在另一篇名为弱类型语言的文章中,作者说Perl弱类型仅仅是因为我可以将字符串连接成数字,反之亦然,而无需任何显式转换。

佩尔

$a=10;
$b="a";
$c=$a.$b;
print $c; #10a

因此,同一示例使Perl的类型较弱,但Java和C#?的类型却没有。

真是的 在此处输入图片说明

作者似乎暗示一种阻止对不同类型的值执行某些操作的语言是强类型的,而相反的意思是弱类型。

因此,在某些时候,我感到被提示相信,如果一种语言在类型之间提供大量自动转换或强制转换(例如perl),最终可能会被认为是弱类型,而其他仅提供少量转换的语言可能最终会被视为弱类型。被认为是强类型的。

但是,我倾向于相信,在这种相互交流中我一定是错的,我只是不知道为什么或如何解释它。

因此,我的问题是:

  • 语言真正弱键入到底意味着什么?
  • 您能否提及与该语言完成的自动转换/自动强制无关的弱类型的任何好例子?
  • 语言可以同时弱输入和强输入吗?

8
强类型与弱类型都是关于类型转换的(它还有什么用?)如果您想使用“非常”弱语言的示例,请观看以下内容:destroyallsoftware.com/talks/wat
野鸭2012年

2
@Wildduck所有语言都提供类型转换,但并非所有语言都被视为弱类型。下面显示的示例展示了程序员如何根据与强类型其他语言相同的示例来考虑弱类型语言。因此,我的问题仍然存在。有什么区别?
Edwin Dalorzo'3

1
我认为,简短的答案是“类型性”不是二进制状态。Java和C#的类型更强,但不是绝对的。
Jodrell 2012年

3
我相信这更适合软件工程
zzzzBov 2012年

4
@Brendan如何将浮点数和整数相加?整数不是在Python中被强制转换为浮点数吗?您现在要说Python不是绝对强类型吗?
Edwin Dalorzo

Answers:


210

更新:这个问题是我在2012年10月15日发布的博客的主题。感谢您提出的伟大问题!


语言“弱类型化”的真正含义是什么?

它的意思是“这种语言使用的类型系统令人讨厌”。相比之下,“强类型”语言是具有令人愉悦的类型系统的语言。

这些术语本质上是没有意义的,您应该避免使用它们。维基百科列出了“强类型”的十一种不同含义,其中有几种是矛盾的。这表明在涉及术语“强类型”或“弱类型”的任何对话中,造成混乱的可能性很高。

您真正可以肯定地说的是,正在讨论的“强类型”语言在类型系统上有一些其他限制,无论是在运行时还是编译时,都缺乏在讨论中的“弱类型”语言。没有进一步的上下文,就无法确定该限制是什么。

不应使用“强类型”和“弱类型”,而应详细描述您所指的类型安全。例如,C#在大多数情况下静态类型的语言,类型安全的语言和内存安全的语言。C#允许违反所有三种“强”类型的输入形式。强制转换运算符违反静态类型;它对编译器说:“我比您更了解此表达式的运行时类型”。如果开发人员错误,则运行时将抛出异常以保护类型安全。如果开发人员希望破坏类型安全性或存储安全性,则可以通过制作“不安全”块来关闭类型安全性系统来做到这一点。在不安全的块中,您可以使用指针魔术来将int视为浮点型(违反类型安全性)或写入您不拥有的内存。(破坏内存安全。)

C#施加了在编译时和运行时都进行检查的类型限制,因此与进行较少的编译时检查或较少的运行时检查的语言相比,C#使其成为“强类型”语言。C#还允许您在特殊情况下绕这些限制进行最终运行,与不允许您进行此类最终运行的语言相比,它成为“弱类型”语言。

到底是什么 很难说。这取决于说话者的观点及其对各种语言功能的态度。


14
@edalorzo:它基于以下方面的品味和个人见解:(1)类型理论的哪些方面是相关的,哪些是不相关的;(2)是否需要一种语言来强制或仅仅鼓励类型限制。正如我指出的那样,可以合理地说C#是强类型的,因为它允许并鼓励静态类型,而可以合理地说C#是弱类型的,因为它允许违反类型安全性。
埃里克·利珀特

4
@edalorzo:关于组装,同样,这是见仁见智。汇编语言编译器不允许您将堆栈中的64位double移到32位寄存器中。它将允许您将32位指针从堆栈中移至64位double处,并移入32位寄存器。从这种意义上讲,该语言是“类型安全”的-它基于数据的类型分类对程序的合法性施加了限制。该限制是“强”还是“弱”是一个意见问题,但这显然是一个限制。
埃里克·利珀特

2
我想我现在明白您的观点,真正弱类型的语言将必须完全没有类型或单一类型,这在现实生活中几乎是不可能的。这样,任何一种语言都有一定的类型定义,这些类型是安全的,并且取决于该语言提供的违反或操纵其数据或数据类型的漏洞数量,您最终可能会考虑或多或少地使用弱类型,甚至在仅在某些情况下。
Edwin Dalorzo'3

7
@edalorzo:是的。例如,未类型化的lambda演算大约与您能得到的弱类型化一样。每个功能都是从功能到功能的功能;任何数据都可以不受限制地传递给任何函数,因为所有事物都是“相同类型”。在无类型lambda演算中,表达式的有效性仅取决于其语法形式,而不取决于将某些表达式归类为某些类型的语义分析。
埃里克·利珀特

3
@Mark我会再给他+1,因为他预测每个人都会对此主题提供不同的解释。这个“弱打字”似乎是一个“神话概念”或一个“城市传奇”,每个人都看到了,但是没有人能证明它的存在:-)
Edwin Dalorzo 2012年

64

正如其他人指出的那样,术语“强类型”和“弱类型”具有许多不同的含义,因此您的问题没有一个答案。但是,由于您在问题中特别提到了Perl,因此让我尝试解释Perl弱键入的含义。

关键是,在Perl中,没有“整数变量”,“浮点变量”,“字符串变量”或“布尔变量”之类的东西。实际上,据用户所知(通常),甚至没有整数,浮点数,字符串或布尔:您所拥有的都是“标量”,它们同时是所有这些东西。因此,您可以例如编写:

$foo = "123" + "456";           # $foo = 579
$bar = substr($foo, 2, 1);      # $bar = 9
$bar .= " lives";               # $bar = "9 lives"
$foo -= $bar;                   # $foo = 579 - 9 = 570

当然,正如您正确指出的那样,所有这些都可以看作是强制类型。但是关键是,在Perl中,类型始终是强制的。实际上,用户很难说出变量的内部“类型”是什么:在我上面的示例的第2行,询问变量的值$bar是字符串"9"还是数字9几乎没有意义,因为就Perl而言,它们是同一回事。实际上,Perl标量甚至有可能在内部同时具有字符串和数字值,例如$foo上面第2行之后的情况。

不利的一面是,由于Perl变量是无类型的(或者,不向用户公开其内部类型),因此不能重载运算符以对不同类型的参数执行不同的操作。您不能只说“此运算符将对数字执行X,对字符串执行Y”,因为该运算符无法(不会)告诉其参数是哪种类型的值。

因此,例如,Perl同时具有并且需要数字加法运算符(+)和字符串连接运算符(.):如上所述,添加字符串("1" + "2" == "3")或连接数字(1 . 2 == 12)很好。同样,数字比较操作符==!=<><=>=<=>比较它们的参数的数值,而字符串比较操作符eqneltgtlegecmp字典顺序比较它们为字符串。所以2 < 10,但是2 gt 10(但是"02" lt 10,虽然"02" == 2)。(请注意,某些其他语言(例如JavaScript)会尝试容纳类似Perl的弱类型做运算符重载。这通常会导致丑陋,例如失去与+。)的关联性。

(美中不足的是,由于历史原因,Perl 5确实有一些极端情况,例如按位逻辑运算符,其行为取决于其参数的内部表示。通常认为这是令人讨厌的设计缺陷,因为内部表述可能会由于令人惊讶的原因而发生变化,因此仅预测那些操作员在给定情况下的操作可能很棘手。)

综上所述,可以说Perl 确实具有强类型。它们不是您可能期望的那种类型。具体来说,除了上面讨论的“标量”类型外,Perl还具有两种结构化类型:“数组”和“哈希”。这些是非常从标量不同,到了那里的Perl变量具有不同的点印记,指示它们的类型($用于标量,@数组,%对于散列)1。有这些类型之间的强制规则,这样你就可以写例如%foo = @bar,但其中不少是相当有损耗:例如,$foo = @bar分配长度的数组 @bar$foo,而不是其内容。(此外,还有其他一些奇怪的类型,例如typeglob和I / O句柄,您通常不会看到它们是公开的。)

同样,在这种出色的设计中,有一个小缺点是引用类型的存在,它们是一种特殊的标量(可以使用ref运算符将其与普通标量区分开)。可以将引用用作普通标量,但是它们的字符串/数字值并不是特别有用,并且如果您使用普通标量操作对其进行修改,它们往往会失去其特殊的引用性。同样,任何Perl变量2都可以作为范例。通常的意见是,如果您发现自己在Perl中检查了对象的类,则说明您做错了什么。bless编入一个类,将其变成该类的对象。Perl中的OO类系统在某种程度上与上述原始类型(或无类型性)系统正交,尽管它在遵循鸭子类型的意义上也是“弱”的


1实际上,印记表示被访问的值的类型,以使得例如在阵列中的第一标@foo$foo[0]。有关更多详细信息,请参见perlfaq4

2(通常)通过引用访问Perl中的对象,但实际上得到的bless是引用所指向的(可能是匿名的)变量。但是,祝福实际上是变量的属性,而不是变量的值,因此,例如,将实际的祝福变量分配给另一个变量,只会给您一个浅浅的,没有祝福的副本。有关更多详细信息,请参见perlobj


19

除了Eric所说的以外,请考虑以下C代码:

void f(void* x);

f(42);
f("hello");

与诸如Python,C#,Java或其他语言之类的语言相比,上面的类型是弱类型的,因为我们会丢失类型信息。Eric正确指出,在C#中,我们可以通过强制转换来绕过编译器,有效地告诉它“我比您更了解此变量的类型”。

但是即使那样,运行时仍会检查类型!如果强制转换无效,则运行时系统将对其进行捕获并引发异常。

使用类型擦除不会发生这种情况–类型信息会被丢弃。强制转换void*为C可以做到这一点。在这方面,以上内容与C#方法声明(例如)从根本上有所不同void f(Object x)

(从技术上讲,C#还允许通过不安全的代码或编组来擦除类型。)

是尽可能弱的类型。其他的一切只是一个静态还是动态类型检查,即时间的事一个类型被选中。


1
+1好点了,您现在使我想到了类型擦除,它也可以表示“弱类型”。Java中也有类型擦除,并且在运行时,类型系统会让您违反编译器永远不会批准的约束。C例子很好地说明了这一点。
Edwin Dalorzo'3

1
同意,洋葱或地狱有几层。这些似乎是类型弱点的更重要定义。
Jodrell 2012年

1
@edalorzo我认为这不太一样,因为即使Java允许您规避编译器,运行时类型系统仍会捕获到违规。因此,Java运行时类型系统在这方面是强类型的(存在例外,例如,可以使用反射来规避访问控制)。
康拉德·鲁道夫2012年

1
@edalorzo您只能以这种方式规避编译器,而不是运行时系统。必须意识到,诸如Java和C#(在某种程度上还包括C ++)之类的语言的类型系统必须得到两次保证:一次在编译时,一次在运行时。void*突破了两个类型检查。泛型类型擦除不是,它只是绕过了编译时检查。在这方面,这就像显式强制转换(由Eric提到)一样。
康拉德·鲁道夫2012年

1
@edalorzo关于您的困惑:我们不应该这样。区别是流利的。是的,类型擦除使Java在这方面的类型较弱。我的观点是,即使使用通用类型擦除,除非您也使用反射,否则您仍然无法规避运行时类型检查。
康拉德·鲁道夫2012年

14

Wikipedia的“强类型”文章就是一个很好的例子:

通常,强类型意味着编程语言对允许发生的混合进行了严格的限制。

弱打字

a = 2
b = "2"

concatenate(a, b) # returns "22"
add(a, b) # returns 4

强类型

a = 2
b = "2"

concatenate(a, b) # Type Error
add(a, b) # Type Error
concatenate(str(a), b) #Returns "22"
add(a, int(b)) # Returns 4

请注意,弱类型的语言可以混合不同类型而不会出错。强类型语言要求输入类型为预期类型。在强类型语言中,可以转换类型(str(a)将整数转换为字符串)或强制转换(int(b))。

这一切都取决于键入的解释。


3
但这导致问题中提供了矛盾的例子。强类型语言可能包含隐式强制,这意味着您的两个“类型错误”示例中的一个(或两个)都会自动转换为后两个示例中的相关内容,但通常该语言仍是强类型。
马克·赫德2012年

3
真正。我猜你可以说强打字和弱打字的程度不同。隐式转换可能意味着该语言的类型不如不进行隐式转换的语言。
SaulBack 2012年

4

我想通过自己对这个问题的研究来为讨论做出贡献,正如其他人评论并做出贡献一样,我一直在阅读他们的答案并遵循他们的参考文献,并且发现了有趣的信息。如建议的那样,在程序员论坛中可能会更好地讨论其中的大多数内容,因为它似乎是理论上的而非实际的。

从理论的角度来看,我认为Luca Cardelli和Peter Wegner撰写的关于理解类型,数据抽象和多态性的文章是我所读过的最好的论据之一。

一种类型可以看作是一套衣服(或盔甲),可以保护基础的无类型表示形式免受任意使用或非预期使用。它提供了一个保护性遮盖物,该遮盖物隐藏了底层表示并限制了对象与其他对象交互的方式。在无类型的系统中,无类型的对象是裸露 的,其基础表示形式公开给所有人看。违反字体系统需要脱下防护服并直接在裸露的衣服上操作。

该说法似乎表明,弱类型输入将使我们能够访问类型的内部结构并像对待其他类型(另一种类型)一样对其进行操作。也许我们可以用不安全的代码(由Eric提及)或由Konrad提及的用c类型擦除的指针来做。

文章继续...

所有表达式类型一致的语言称为强类型语言。如果语言是强类型的,则其编译器可以保证所接受的程序将在没有类型错误的情况下执行。通常,我们应该努力实现强类型化,并在可能的情况下采用静态类型。请注意,每种静态类型的语言都是强类型的,但相反不一定是正确的。

因此,强类型表示没有类型错误,我只能假设弱类型意味着相反:可能存在类型错误。在运行时还是编译时?在这里似乎无关紧要。

有趣的是,按照该定义,具有强大类型强制性的语言(如Perl)将被视为强类型化的,因​​为系统不会失败,但是它通过将类型强制为适当的和定义良好的对等来处理类型。

另一方面,我是否可以说ClassCastExceptionArrayStoreException(在Java中)和InvalidCastExceptionArrayTypeMismatchException(在C#中)的允许表示至少在编译时处于弱类型的水平?埃里克的答案似乎同意这一点。

在此问题的答案之一提供的参考文献之一中提供的第二篇名为类型化编程的文章中,Luca Cardelli深入研究了类型冲突的概念:

大多数系统编程语言都允许任意类型的违反,有些是不加区分的,有些仅在程序的受限部分中。涉及类型冲突的操作称为不健全。类型违规分为几类[我们可以提到]:

基本值强制:包括整数,布尔值,字符,集合等之间的转换。这里不需要类型冲突,因为可以提供内置接口来以类型健全的方式执行强制。

这样,像操作员提供的那样的类型强制可以被认为是类型冲突,但是除非它们破坏了类型系统的一致性,否则我们可以说它们不会导致弱类型系统。

基于此,Python,Perl,Java或C#都不是弱类型。

Cardelli提到了两个类型错误,我很好地考虑了真正弱类型的情况:

地址算术。如有必要,应该有一个内置的(不健全的)接口,提供对地址和类型转换的适当操作。各种情况都涉及到堆的指针(对于重定位收集器非常危险),指向堆栈的指针,指向静态区域的指针以及指向其他地址空间的指针。有时,数组索引可以代替地址算法。 内存映射。这涉及将内存区域视为非结构化数组,尽管它包含结构化数据。这是内存分配器和收集器的典型特征。

诸如C(由Konrad提及)或.Net中不安全代码(由Eric提及)之类的语言中可能发生的这类事情实际上暗示着弱键入。

我相信到目前为止,最好的答案是埃里克(Eric),因为这个概念的定义是非常理论性的,当涉及到特定语言时,对所有这些概念的解释可能会得出不同的结论。


4

弱类型的确确实意味着可以隐式强制转换很大比例的类型,试图猜测编码器的意图。

强类型意味着没有强制类型,或者至少没有强制类型。

静态类型意味着您的变量类型在编译时确定。

最近,许多人将“明显键入”与“强烈键入”混淆。“清单式输入”是指您明确声明变量的类型。

Python通常是强类型的,尽管您可以在布尔上下文中使用几乎所有内容,布尔值可以在整数上下文中使用,并且您可以在浮点上下文中使用整数。它没有明显的类型,因为您不需要声明您的类型(Cython除外,尽管它很有趣,但它并不完全是python)。它也不是静态类型的。

C和C ++是明显类型化,静态类型化和某种程度强类型化的,因​​为您声明类型,类型是在编译时确定的,并且可以混合使用整数和指针,整数和双精度,甚至将指向一种类型的指针转​​换为指向另一种类型的指针。

Haskell是一个有趣的示例,因为它不是显式键入的,而是静态和强类型的。


+1是因为我喜欢“ manifestly typed”一词,该术语对Java和C#等语言进行了分类,在这些语言中,您必须显式声明类型,并将它们与其他静态类型的语言(如Haskell和Scala)区分开,其中类型推断在其中起着重要的作用,通常正如您所说,使人们感到困惑,并使他们相信这些语言是动态类型的。
Edwin Dalorzo

3

强<=>弱类型不仅是关于一种数据类型的语言将语言自动将多少值强制转换为另一种数据的连续性,还涉及到对实际的强弱程度。在Python和Java中,大多数情况下在C#中,值的类型设置为固定。在Perl中,不是那么多-实际上只有少数几个不同的值类型可以存储在变量中。

让我们一一打开案例。


蟒蛇

在Python示例中1 + "1"+运算符调用__add__for类型int,将字符串"1"作为参数,但是这会导致NotImplemented:

>>> (1).__add__('1')
NotImplemented

接下来,解释器尝试__radd__str的:

>>> '1'.__radd__(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute '__radd__'

由于失败,+操作员将结果与失败TypeError: unsupported operand type(s) for +: 'int' and 'str'。这样,该异常并不能说明强类型,但是该运算符+ 不会自动将其参数强制转换为同一类型,这说明了Python不是连续体中最弱类型的语言。

另一方面,在Python 'a' * 5 实现了:

>>> 'a' * 5
'aaaaa'

那是,

>>> 'a'.__mul__(5)
'aaaaa'

操作不同的事实需要强类型化-但是,*在乘法之前将值强制转换为数字的相反情况并不一定会使值弱类型化。


爪哇

Java示例String result = "1" + 1;之所以起作用,仅是因为为方便起见,运算符+被字符串重载。Java +运算符使用创建一个替换序列StringBuilder(请参阅参考资料):

String result = a + b;
// becomes something like
String result = new StringBuilder().append(a).append(b).toString()

这是一个非常静态的键入的示例,没有实际的强制性- StringBuilder有一种append(Object)专门用于此的方法。该文档说:

追加Object参数的字符串表示形式。

总体效果就好像参数已由方法转换为String.valueOf(Object)字符串,然后将该字符串的字符附加到此字符序列。

String.valueOf

返回Object参数的字符串表示形式。[返回]如果参数为null,则字符串等于"null"; 否则,obj.toString()返回的值。

因此,这种情况绝对不会被语言强制-将所有问题都委派给对象本身。


C#

根据此处Jon Skeet答案,该类+甚至都不会重载运算符string-类似于Java,这归功于静态和强类型化,这是编译器生成的便利。


佩尔

正如perldata解释的那样,

Perl具有三种内置数据类型:标量,标量数组和标量的关联数组,称为“哈希”。标量是单个字符串(任何大小,仅受可用内存限制),数字或对某物的引用(将在perlref中进行讨论)。普通数组是按数字索引的标量的有序列表,从0开始。哈希是通过其关联的字符串键索引的无序标量值的集合。

但是,Perl没有用于数字,布尔值,字符串,空值,undefineds,对其他对象的引用等的单独数据类型-它仅具有一种用于所有这些的类型,即标量类型。0是“ 0”的标量值。设置为字符串的标量变量实际上可以变成数字,并且从此开始,如果在数字上下文中访问则其行为就不同于“只是字符串”。标量可以在Perl中容纳任何内容,它与系统中存在的对象一样多。而在Python中,名称仅指对象,而在Perl中,名称中的标量值是可变对象。此外,基于对象的类型系统还基于此:perl中只有3种数据类型-标量,列表和哈希。Perl中的用户定义对象是对包的引用(指向之前3个中的任何一个的指针)bless-您可以获取任何此类值,并在需要的任何时候将其祝福给任何类。

Perl甚至允许您一时兴起地更改值的类-在Python中这是不可能的,在Python中创建某些类的值时,您需要显式构造具有该类object.__new__或类似值的该类的值。在Python中,创建后实际上不能更改对象的本质,在Perl中,您可以做很多事情:

package Foo;
package Bar;

my $val = 42;
# $val is now a scalar value set from double
bless \$val, Foo;
# all references to $val now belong to class Foo
my $obj = \$val;
# now $obj refers to the SV stored in $val
# thus this prints: Foo=SCALAR(0x1c7d8c8)
print \$val, "\n"; 
# all references to $val now belong to class Bar
bless \$val, Bar;
# thus this prints Bar=SCALAR(0x1c7d8c8)
print \$val, "\n";
# we change the value stored in $val from number to a string
$val = 'abc';
# yet still the SV is blessed: Bar=SCALAR(0x1c7d8c8)
print \$val, "\n";
# and on the course, the $obj now refers to a "Bar" even though
# at the time of copying it did refer to a "Foo".
print $obj, "\n";

因此,类型标识弱绑定到变量,并且可以通过任何引用即时更改它。实际上,如果您这样做

my $another = $val;

\$another没有类标识,即使仍然\$val会提供祝福的引用。


TL; DR

对于Perl而言,弱类型不仅仅是自动强制,还有很多更多的是,值的类型本身并没有固定不变,这与Python是动态但非常强类型的语言不同。这蟒蛇给人TypeError1 + "1"是一种迹象表明,语言是强类型,即使做一些有用的一个相反,如Java或C#不排除他们是强类型语言。


这是完全混乱的。Perl 5 变量不具有类型不影响value,后者始终具有类型。
Jim Balter

@JimBalter很好,是的,值的类型是字符串或数字,根据标量变量是否包含字符串或数字,它在某些情况下的行为可能有所不同。但是包含在变量中的值可以通过访问变量来更改类型,并且由于值本身存在变量中,因此可以将值本身视为在类型之间是可变的。
Antti Haapala'6

值不会改变类型-这是不连贯的;值始终是类型。变量包含的值可以更改。从1到“1”的变化是一样多的一个中值从1到2的变化的变化
吉姆巴尔特

诸如Perl之类的弱类型语言允许值的前一种类型根据上下文隐式发生。但是,即使C ++也允许通过运算符定义进行此类隐式转换。正如Eric Lippert指出的那样,弱类型输入是一个非常非正式的属性,并且实际上不是描述语言的有用方法。
吉姆·巴尔特

PS可以证明,即使在Perl中,<digits>和“ <digits>”也具有不同的值,而不仅仅是不同的类型。在大多数情况下,Perl 通过隐式转换使<digits>和“ <digits>” 看起来具有相同的值,但这种幻想并不完整。例如“ 12” | “ 34”是36,而12 | 34是46。另一个示例是,在大多数情况下,“ 00”在数值上均等于00,但在布尔值上下文中并非如此,其中“ 00”为true,而00为false。
Jim Balter

1

正如许多其他人所表示的那样,“强”键入与“弱”键入的整个概念都是有问题的。

作为一个原型,Smalltalk是非常强类型的- 如果两个对象之间的操作不兼容,它将始终引发异常。但是,我怀疑此列表中很少有人将Smalltalk称为强类型语言,因为它是动态类型。

我发现“静态”与“动态”打字的概念比“强”与“弱”的打字更有用。静态类型的语言具有在编译时确定的所有类型,否则程序员必须明确声明。

与动态类型语言相反,后者是在运行时执行键入的。这通常是多态语言的要求,因此程序员不必事先确定关于两个对象之间的操作是否合法的决定。

在多态,动态类型的语言(如Smalltalk和Ruby)中,将“类型”视为“符合协议”更为有用。如果一个对象遵循与另一个对象相同的协议(即使两个对象不共享任何继承,混合或其他伏都教),则在运行系统中它们被视为相同的“类型”。更正确地说,此类系统中的对象是自治的,并且可以决定响应任何引用特定参数的特定消息是否有意义。

是否需要一个对象,该对象可以使用描述蓝色的对象参数对消息“ +”做出有意义的响应?您可以在动态类型的语言中执行此操作,但是在静态类型的语言中则很麻烦。


3
我认为动态和静态类型的概念不在讨论中。尽管我不得不说,我不相信多态性在静态类型语言中仍然受到阻碍。最终,类型系统会在运行时或编译时验证给定操作是否适用于给定操作数。另外,其他形式的多态性(例如参数函数和类)允许以静态类型语言的形式组合类型,与动态类型相比,您将其描述为非常困难,如果提供类型推断则更好。
Edwin Dalorzo'4

0

我喜欢@Eric Lippert的答案,但要解决这个问题-强类型语言通常在程序的每个点都具有变量类型的显式知识。弱类型语言不会,因此它们可以尝试执行某种特定类型可能无法执行的操作。它认为最简单的方法是在函数中。C ++:

void func(string a) {...}

a已知该变量的类型为字符串,任何不兼容的操作都将在编译时捕获。

蟒蛇:

def func(a)
  ...

该变量a可以是任何东西,我们可以拥有调用无效方法的代码,该方法只会在运行时被捕获。


12
我认为您可能会混淆动态类型与静态类型与强类型与弱类型。在两个版本的代码中,运行时类型系统都非常了解a是字符串。只是在第一种情况下,编译器可以告诉您,在第二种情况下则不能。但是,这不会使这些语言中的任何一种都变得虚弱。
Edwin Dalorzo 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.