为什么动态类型语言不让开发人员指定类型?


14

我所知道的动态类型语言从不让开发人员指定变量的类型,或者至少对这种类型的支持非常有限。

例如,JavaScript方便时不提供任何机制来强制变量类型。PHP使您可以指定一些类型的方法参数,但是无法使用本机类型(intstring,等)的参数,也没有办法强制类型的参数比任何其他。

同时,可以方便地选择以动态类型语言指定变量的类型,而不是手动进行类型检查。

为什么会有这样的限制?是出于技术/性能方面的原因(我认为是JavaScript)还是出于政治方面的原因(我认为是PHP)?我不熟悉的其他动态类型语言是否属于这种情况?


编辑:在回答和评论之后,这是一个澄清的示例:假设我们在纯PHP中具有以下方法:

public function CreateProduct($name, $description, $price, $quantity)
{
    // Check the arguments.
    if (!is_string($name)) throw new Exception('The name argument is expected to be a string.');
    if (!is_string($description)) throw new Exception('The description argument is expected to be a string.');
    if (!is_float($price) || is_double($price)) throw new Exception('The price argument is expected to be a float or a double.');
    if (!is_int($quantity)) throw new Exception('The quantity argument is expected to be an integer.');

    if (!$name) throw new Exception('The name argument cannot be an empty string.');
    if ($price <= 0) throw new Exception('The price argument cannot be less or equal to zero.');
    if ($price < 0) throw new Exception('The price argument cannot be less than zero.');

    // We can finally begin to write the actual code.
    // TODO: Implement the method here.
}

通过一些努力,可以将其重写为(另请参见PHP中的按合同编程):

public function CreateProduct($name, $description, $price, $quantity)
{
    Component::CheckArguments(__FILE__, __LINE__, array(
        'name' => array('value' => $name, 'type' => VTYPE_STRING),
        'description' => array('value' => $description, 'type' => VTYPE_STRING),
        'price' => array('value' => $price, 'type' => VTYPE_FLOAT_OR_DOUBLE),
        'quantity' => array('value' => $quantity, 'type' => VTYPE_INT)
    ));

    if (!$name) throw new Exception('The name argument cannot be an empty string.');
    if ($price <= 0) throw new Exception('The price argument cannot be less or equal to zero.');
    if ($price < 0) throw new Exception('The price argument cannot be less than zero.');

    // We can finally begin to write the actual code.
    // TODO: Implement the method here.
}

但是,如果PHP可以选择接受本机类型作为参数,则相同的方法将编写如下:

public function CreateProduct(string $name, string $description, double $price, int $quantity)
{
    // Check the arguments.
    if (!$name) throw new Exception('The name argument cannot be an empty string.');
    if ($price <= 0) throw new Exception('The price argument cannot be less or equal to zero.');
    if ($price < 0) throw new Exception('The price argument cannot be less than zero.');

    // We can finally begin to write the actual code.
    // TODO: Implement the method here.
}

哪一个更短?哪一个更容易阅读?


1
您可以选择使用某些动态类型化的语言(例如Common Lisp)指定类型。
SK-logic

不少动态类型化语言使用强制转换来强制类型化……
Trezoid 2011年

有的。例如,Objective-C是动态类型的,但是您可以声明变量的类型,如果没有得到所需的类型,编译器将发出警告。
mipadi

1
Clojure是一种语言的示例,该语言通常是动态键入的,但是您可以选择通过“类型提示”提供变量类型(通常仅在需要获得编译时类型信息的性能优势的情况下执行此操作)
mikera 2011年

1
Groovy是动态类型化语言的另一个示例,该语言允许指定类型。
埃里克·威尔逊

Answers:


17

进行静态类型化的目的是能够静态地证明您的程序在类型方面是正确(请注意:在所有方面都不完全正确)。如果整个系统都具有静态类型系统,则大多数时候可以检测到类型错误。

如果只有部分类型信息,则只能检查恰好类型信息完整的调用图的一小部分。但是您已经花了很多时间和精力为不完整的零件指定类型信息,在这种情况下您无济于事,但会给人一种错误的安全感。

要表达类型信息,您需要一部分语言,不能过分简单。很快您就会发现类似的信息int还不够;你会想要像List<Pair<Int, String>>,然后是参数类型,等等。即使在Java的简单情况下,也可能造成混乱。

然后,您需要在翻译阶段处理这些信息执行阶段,因为仅检查静态错误是很愚蠢的。如果完全指定,用户将期望类型约束始终成立。动态语言的发展速度并没有那么快,而这种检查会进一步降低性能。静态语言会花大量精力检查类型,因为它只会做一次。动态语言不能。

现在想象添加和维护所有这些功能,以便人们有时可以选择使用这些功能,而仅检测到一小部分类型错误。我认为这样做不值得。

动态语言的重点是拥有一个非常小且非常具有延展性的框架,在该框架中,您可以轻松地完成以静态语言完成时涉及更多的事情:用于元编程,嘲笑和测试,动态替换代码等。Smalltalk和Lisp都非常动态,将其极端化了,可以发送环境映像而不是从源代码构建。但是,当您要确保特定的数据路径是类型安全的时,请添加断言并编写更多的单元测试。


1
+1,尽管测试只能显示在某些情况下不会发生错误。它们不能替代(类型)错误是不可能的证明。

1
@Ingo:当然。但是动态语言非常适合修改和快速制作原型,您可以在其中快速表达相对简单的想法。如果您想要防弹的生产代码,则在提取了一些稳定的核心组件之后,可以使用静态语言。
9000

1
@ 9000,我毫不怀疑他们很棒。只是要指出不是编写3或4个me脚测试,并且不能确保类型为saftey
Ingo

2
@ 9000,是的,坏消息是即使在那时,它实际上也是不可能的。甚至Haskell或Agda代码都依赖于assumptios,例如,运行时使用的库是正确的。就是说,在一个具有1000个LOC且分布在十几个源代码文件中的项目中,当您可以更改某些内容时真是太酷了,而且您知道编译器将指向更改会产生影响的每一行。
Ingo

4
写得不好的测试不能代替静态类型检查:它们是劣等的。编写良好的测试也不能替代静态类型检查:它们是优越的。
Rein Henrichs

8

在大多数动态语言中,您至少可以动态测试对象或值的类型。

还有一些动态语言的静态类型推断器,检查器和/或执行器:

Perl 6将支持带有静态类型的可选 类型系统


但我想最重要的是,很多人使用动态语言 是因为它们是动态类型的,对于他们来说,可选的静态类型非常“嗡嗡”。许多其他人使用它们是因为它们“很容易被非程序员使用”,这在很大程度上是宽容的自然动态键入的结果。对他们来说,可选类型是他们不会理解或不会被使用的东西。

如果您持愤世嫉俗的话,可以说可选的静态类型会同时兼顾两个方面。对于静态类型狂热者,它不能防止所有动态类型失败。对于动态型风扇,它仍然是一件直筒外套……尽管束带没有扎紧。


2
应当指出,在大多数情况下,大多数社区都不愿意自己检查类型。在处理对象层次结构时,请使用多态性(特别是“鸭子类型”),如果可能/合理的话,将其强制转换为期望的类型。在少数情况下,根本不允许任何类型,但是在许多语言中,无论如何大多数情况下都会出现异常,因此类型检查很少有用。

4
“人们通常使用动态语言,因为它们是动态键入的”:使用JavaScript,因为它是大多数浏览器唯一支持的语言。使用PHP是因为它很流行。
阿森尼·穆尔琴科(Arseni Mourzenko)2011年

2

JavaScript确实计划包括一些可选的静态类型,而且似乎许多成熟的动态语言正朝着这种方向发展-

原因是当您第一次编码时,您希望快速而动态地键入。一旦您的代码稳定,可以工作并且有很多用途,您就希望锁定设计以减少错误。(这对用户和开发人员都有利,因为前者将在调用时进行错误检查,而后者不会意外损坏。

这对我来说很有意义,因为无论我使用什么语言,通常在项目开始时我都会进行太多类型检查,而在项目生命周期结束时却很少进行类型检查。


我不知道在JavaScript中包含可选静态类型的那些计划。但希望它们不会像ActiveScript中那样残酷。JavaScript和Java中最差的一种。
哈维尔

它计划用于JS 4(或ECMAscript 4),但由于存在争议而将该版本删除。我敢肯定,类似的内容将来会以某种语言出现。(顺便说一句,在Python中,您可以使用装饰器进行排序。)
Macke,

1
装饰器添加动态类型检查,这是一种断言。由于该语言的极端动态性,因此您无法在Python中获得全面的静态类型检查,无论您多么努力,都无法进行检查。
9000

@ 9000:是的。但是,我并不认为动态类型检查很糟糕(但是我更喜欢鸭子类型比较ala JS4),尤其是在与单元测试结合使用时,对修饰符进行类型化可能更有用,因为它们支持IDE / lint-checker。标准化。
Macke,

当然还不错!这不是道德问题。在某些时候,必须以一种或另一种方式“检查”类型。如果在C语言中编写*((double *)0x98765E),CPU会执行此操作,并检查0x98765E是否确实是一个指向double的指针。
Ingo

2

Python对象确实具有类型。

您可以在创建对象时指定类型。

同时,可以方便地选择以动态类型语言指定变量的类型,而不是手动进行类型检查。

实际上,在Python中进行手动类型检查几乎总是在浪费时间和代码。

用Python编写类型检查代码只是一个不好的做法。

如果某些恶意社交行为者使用了不合适的类型,那么当该类型不合适时,Python的普通方法将引发一个普通异常。

您不编写代码,但程序仍然失败,并显示 TypeError

在极少数情况下,您必须在运行时确定类型。

为什么会有这样的限制?

由于它不是“限制”,因此该问题不是真正的问题。


2
“ Python对象确实具有类型。” - 真的?就像perl对象,PHP对象和世界上所有其他数据项一样。静态类型和动态类型之间的区别仅在于要检查类型时,即类型错误显现出来时。如果它们显示为编译器错误,则为静态类型,如果显示为运行时错误,则为动态类型。
Ingo

@Ingo:感谢您的澄清。问题在于C ++和Java对象可以从一种类型转换为另一种类型,从而使对象的类型有些模糊,因此,这些编译器中的“类型检查”也有些模糊。即使在运行时,Python类型检查的地方也不是那么模糊。同样,这个问题有点接近说动态类型的语言没有类型。好消息是它不会犯该常见错误。
S.Lott

1
是的,类型转换(与类型转换相反,即((double)42))颠覆了静态类型。当类型系统功能不够强大时,需要使用它们。在Java 5之前,Java没有可参数化的类型,那么,如果没有类型转换,就无法生存。如今情况已经好多了,但是类型系统仍然缺少高级类型,更不用说高级多态了。我认为动态类型化的语言很可能会吸引如此多的追随者,正是因为它们从过于狭窄的类型系统中解放了一种。
Ingo

2

大多数时候,您不需要,至少不需要您所建议的详细程度。在PHP中,您使用的运算符使您可以清楚地了解参数的期望值。尽管PHP会尽可能地转换您的值,但这只是设计上的疏忽,即使您将数组传递给需要字符串的操作时,由于转换并不总是有意义,有时也会得到奇怪的结果(而这也正是类型检查有用的)。除此之外,是否添加整数15或字符串"1"以及"5" -这一事实,你正在使用的+运算符向PHP发出信号,告知您要将参数视为数字,然后PHP会遵守。一种有趣的情况是,当您从MySQL接收查询结果时:许多数字值只是作为字符串返回,但是您不会注意到,因为每当您将它们视为数字时,PHP都会为它们强制转换。

Python在类型方面有些严格,但与PHP不同,Python从一开始就具有例外,并始终如一地使用它。“更容易要求宽恕而不是允许”范式建议仅执行操作而不进行类型检查,并依靠在类型没有意义时引发的异常。我能想到的唯一缺点是,有时您会发现某个类型与您期望的类型不匹配,但是找到原因可能很乏味。

而且还有另外一个原因来考虑:动态语言不具有一个编译阶段。即使你有型的限制,他们只能火在运行,只是因为没有编译时间。如果您的检查仍然导致运行时错误,则对它们进行相应建模要容易得多:作为显式检查(例如is_XXX()在PHP或typeofjavascript中),或者通过抛出异常(例如Python)。从功能上讲,您具有相同的效果(当类型检查失败时在运行时会发出错误信号),但是它可以与语言的其余语义更好地集成在一起。用动态语言来处理根本不同于其他运行时错误的类型错误根本就没有意义。


0

您可能对Haskell感兴趣-它的类型系统可以从代码中推断类型,还可以指定类型。


5
Haskell是一门很棒的语言。在某种程度上,它与动态语言相反:您花费大量时间描述类型,通常一旦弄清类型,程序
9000

@ 9000:的确如此。编译后,通常可以正常工作。:)
Macke

@Macke- 当然,通常具有不同的值。:-)对我来说,类型系统和功能范式的最大好处是,正如我在其他地方指出的那样,不必担心某个地方的更改是否会静默地影响其他地方的某些依赖代码-编译器会指出类型错误可变状态就不存在了。
Ingo

0

正如其他答案所暗示的那样,在实现编程语言时有两种输入方法。

  1. 让程序员告诉您所有用于类型的变量和函数。理想情况下,您还要验证类型规格是否正确。然后,由于您知道每种地方都有什么类型的事物,因此您可以编写代码,假设适当的事物在那里,并使用您用来直接实现该类型的任何数据结构。
  2. 将类型指示器附加到将存储在变量中并传递给函数并从函数返回的值。这意味着程序员不必为变量或函数指定任何类型,因为类型实际上属于变量和函数所引用的对象。

两种方法都是有效的,使用哪种方法部分取决于技术方面的考虑,例如性能,部分取决于政治原因,例如语言的目标市场。


0

首先,动态语言的创建主要是为了易于使用。正如您所提到的,自动进行类型转换并为我们提供较少的开销确实非常好。但与此同时,它也缺少性能问题。

在不担心性能的情况下,您可以坚持使用动态语言。例如,当JavaScript需要在程序中执行许多类型转换时,它的运行速度会变慢,但它有助于减少代码中的行数。

值得一提的是,还有其他动态语言甚至允许程序员指定类型。例如Groovy是在JVM上运行的著名动态语言之一。而且最近几天也非常有名。请注意,Groovy的性能与Java相同。

希望对您有帮助。


-1

这样做根本没有意义。

为什么?

因为DTL的类型系统恰好使得在编译时无法确定类型。因此,编译器甚至无法检查指定的类型是否有意义。


1
为什么?提示编译器期望什么类型是非常有意义的。它不会与任何类型系统约束相矛盾。
SK-logic

1
SK-logic:如果动态类型化意味着每个函数/方法/操作都采用类型为“ Dynamic”,“ Any”或任何类型的对象并返回“ Dynamic”,“ Any”的任何类型,则通常无法分辨出某个值例如,将始终为整数。因此,运行时代码无论如何都必须检查非整数,就像类型首先是“动态”一样。这就是静态类型系统所做的事情:它可以证明某个变量,字段或方法返回始终是某种类型。
戈(Ingo)

@Ingo,不,有办法。例如,请参阅如何在Common Lisp中实现它。它对于局部变量特别有用-您可以通过引入所有键入提示来显着提高性能。
SK-logic

@ SK-logic:也许您可以告诉我在CL中何时以及如何检测到类型错误?无论如何,@ MainMa在他/她的问题中很好地总结了现状:这正是人们对“纯”动态语言的期望。
Ingo

@Ingo,是什么让您认为类型仅对静态证明正确性有用?即使对于像C这样的语言,您也可以进行未经检查的类型转换,但事实并非如此。动态语言中的类型注释主要用作编译器提示,以提高性能或指定具体的数字表示形式。我同意在大多数情况下注解不应更改代码的语义。
SK-logic

-1

看一下Go,表面上它是静态类型的,但是这些类型可能是本质上是动态的接口。

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.