[维基百科] 另一方面,许多语言对于人工生成的类型安全证明来说过于庞大,因为它们通常需要检查成千上万种情况。...由于实现中的错误或其他语言编写的链接库中的错误,某些错误可能会在运行时发生;这些错误可能导致特定情况下给定实现的类型不安全。
虽然类型安全和类型系统适用于现实世界的编程,但它们的根源和定义来自于学术界 - 因此,在谈论实际使用的真实编程语言时,“什么是”类型安全的正式定义很难确定。学者们喜欢对称建立小型编程语言,这些语言被称为 玩具语言。只有对于这些语言才能够正式地展示它们是类型安全的(并且证明它们的操作在逻辑上是正确的)。
例如,学者们努力证明 Java 是类型安全的,因此他们创建了一个较小的版本称为 Featherweight Java,并在一篇论文中证明它是类型安全的。同样,Christopher Lyon Anderson 的博士论文选取了 JavaScript 的子集,称其为 JS0 并证明了它是类型安全的。
事实上,像 Python、Java、C++ 这样的正式语言并不完全是类型安全的,因为它们太庞大了。一个微小的错误很容易发生,这会破坏类型系统。
参考文献: http://www.pl-enthusiast.net/2014/08/05/type-safety/ 和 https://en.wikipedia.org/wiki/Type_system
ctypes
,Python 就不是类型安全的。 - Daniel在你最疯狂的梦里也不可能。
#!/usr/bin/python
counter = 100 # An integer assignment
miles = 1000.0 # A floating point
name = "John" # A string
print counter
print miles
print name
counter = "Mary had a little lamb"
print counter
当你运行时,你会看到:python p1.py
100
1000.0
John
Mary had a little lamb
如果一个编程语言可以轻松地将变量的内容从整数转换为字符串,那么无论如何你都不能认为它是“类型安全”的。
在专业软件开发的实际世界中,“类型安全”是指编译器会捕捉到愚蠢的错误。是的,在C/C++中,你可以采取非常规措施来规避类型安全性。你可以声明像这样的内容:
union BAD_UNION
{
long number;
char str[4];
} data;
但是程序员必须付出额外的努力才能做到这一点。我们不需要在Python中走额外的英寸来扭曲计数器变量。
C/C++中的程序员可以通过转换做一些讨厌的事情,但他们必须有意地这样做,而不是无意间。
最容易让你犯错的地方是类转换。当您声明一个带有基类参数的函数/方法,然后传递指向派生类的指针时,您并不总是得到所需的方法和变量,因为方法/函数期望基本类型。如果在您的派生类中覆盖了任何内容,则必须在该方法/函数中加以考虑。
在现实世界中,“类型安全”的语言有助于保护程序员免于无意中做出愚蠢的事情。它还保护人类免受致命伤害。
考虑胰岛素泵或输液泵。它们会将限量的延长生命的化学物质按照所需的速率/间隔注入人体。
现在考虑一下,当存在一个逻辑路径时,泵步进控制逻辑试图将字符串“insulin”解释为要管理的整数量时会发生什么。结果将不会是好的。最有可能是致命的。
>>> 'a' + 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: cannot concatenate 'str' and 'int' objects
由于这种检查只发生在运行时而不是在运行程序之前,因此Python不是一种类型安全的语言(尽管PEP-484除外)。
现在,让我们来谈谈我们的智力挑战函数(sum)。如果sum(a,b)没有指定a和b的类型,则无法进行良好的单元测试。像断言sum(1,1)是2这样的测试是错误的,因为它只涵盖了假定的整数参数。在现实生活中,当a和b是类型雌雄同体时,就没有办法针对函数sum编写真正的单元测试!甚至有些框架假装从上述残缺的测试用例中推导出测试覆盖结果。这是另一个谎言。
这就是我要说的全部内容!感谢您的阅读,我发布这篇文章的唯一原因可能是让您思考这个问题,也许(也许……)有一天会从事软件工程……
一般来说,大规模/复杂系统需要类型检查,首先是在编译时(静态)和运行时(动态)。这不是学术界的问题,而是一个简单、常识性的经验法则,就像“编译器是你的朋友”一样。除了运行时性能影响之外,还有其他重要的影响,如下所示:
可扩展性的三个方面是:
唯一安全的重构方法是对所有内容进行充分测试(使用测试驱动开发或至少单元测试和至少良好的覆盖率测试,这不是质量保证,而是开发/研发)。未覆盖的部分将会出错,这样的系统更像垃圾而不是工程艺术品。
现在假设我们有一个简单的函数sum,返回两个数字的和。可以想象对这个函数进行单元测试,基于已知的参数和返回类型。我们不是在谈论函数模板,它们归结为简单的例子。请编写一个简单的单元测试,测试同样名为sum的函数,其中参数和返回类型可以是任何类型,包括整数、浮点数、字符串和/或任何其他用户定义类型,只要这些类型重载/实现了加号运算符即可。你如何编写这样一个简单的测试用例?!?为了涵盖每种可能的情况,测试用例需要多复杂? if sys.errno:
my_favorite_files.append(sys.errno)
应该使用这个:
if args.errno:
my_favorite_files.append(sys.errno)
将任何东西强制转换为布尔值,因为它使if
语句更容易的做法是我不希望在一种类型安全的语言中找到的。
'1' + 2
。例如,Javascript 就不是类型安全的。 - Eric Duminil