动态打字的生产率预期提高了多少?[关闭]


82

我经常听到这样的说法:动态类型的语言比静态类型的语言更具生产力。提出索赔的原因是什么?难道不只是使用现代概念进行工具处理,例如约定优于配置,使用功能编程,高级编程模型以及使用一致的抽象吗?公认的是,由于不需要(例如在Java中)通常多余的类型声明,因此混乱程度较小,但是您也可以在使用类型推断的静态类型语言中省略大多数类型声明,而不会失去静态类型的其他优点。所有这些都可用于现代静态类型的语言,例如Scala。

那么:对于动态类型的生产力来说,这到底是类型模型本身的优势呢?

澄清:我对大型/中型项目比对快速黑客更感兴趣。:-)


10
您是否希望“静态二重奏”比“动态二重奏”更快或更高效?
Steve314

二重奏是什么意思?无论如何:我可以想到两个原因,即静态类型比动态类型更有效率:更多的编译器检查错误,代码完成,有关程序员意图的更多信息。这就是为什么我要问相反的问题。
汉斯·彼得·斯特尔

11
这是开玩笑的观点。“动态二重奏”是蝙蝠侠和罗宾。如果他们被称为“静态二人组”,他们对哥谭市犯罪黑社会的恐惧就不会那么大。由于开发人员是人,所以不论术语是什么,肤浅的事物都会有所作为。
Steve314

我的第一个问题是我是否知道自己在做什么。如果这样做,那么我可以提前进行设计,并且静态类型化是有意义的。如果我不这样做,那么我将不得不即时更改很多事情,动态键入会更容易。当我不知道自己在做什么时,Common Lisp是我发现的最好的语言。(注意:我只抓过Haskell,因此对推断静态类型没有好感。)
David Thornley

Answers:


99

我实际上认为这是一个非常接近的电话。动态类型和静态类型都有其优点。

动态类型产生更高效率的原因:

  • 更简洁 -如果一切都是动态键入的,则可以删除很多无关的样板代码-类型声明,类型转换逻辑等。在所有其他条件相同的情况下,较短的代码编写速度稍快一些,但更重要的是,它可以更快地读取和编写代码。维护(因为您无需遍历许多代码页即可掌握正在发生的事情)
  • 诸如鸭子打字和猴子修补之类的“黑客”技术更容易获得结果(尽管稍后可能会使您感到困惑...)
  • 更具交互性 -动态类型可以说更适合于类似于REPL的交互式编程,以快速进行原型制作,对正在运行的程序实例进行实时调试,甚至实时编码。
  • 测试用例可能会捕获运行时错误 -假设您正在使用TDD或至少具有良好的测试套件,这应该可以解决代码中的所有键入问题。
  • 更好的多态性 -动态语言可能更可能鼓励创建多态函数和抽象,这可以提高生产力和代码重用。例如Clojure在其许多抽象中都充分利用了动态多态性。
  • 原型 - 在我看来,基于原型的数据/对象模型比静态类型的继承层次结构更强大,更灵活。动态语言更可能允许或鼓励基于原型的方法,Javascript是一个很好的例子。

静态类型产生更高效率的原因:

  • 更好的设计 -被迫预先考虑软件中值的类型可以促使您寻求更清洁,更合乎逻辑的解决方案。(我说可以 -仍然可以设计出非常糟糕的代码...)
  • 更好的编译时检查 -静态类型可以使更多错误在编译时被捕获。这是一个巨大的优势,对于整个静态类型的语言来说,这无疑是最好的选择。
  • 自动完成 -静态类型输入还可以向IDE提供更多信息,从而使代码或文档查找的自动完成更为有效。
  • 不鼓励黑客攻击 -您必须在代码中保持类型约束,这可能是长期可维护性的优势。
  • 类型推断 -在某些语言(例如Scala)中,这可以为您提供动态语言的许多简洁好处,而这些语言仍将保持类型规范。

平均而言,我的结论(经过多年的围栏工作经验)得出的结论是,动态键入在短期内可能会更有效率,但是除非您拥有非常好的测试套件和测试纪律,否则最终很难维护。

另一方面,实际上,我总体上更喜欢使用静态类型的方法,因为从长远来看,正确性的好处和工具支持可为您提供更高的生产率。


14
+1,非常详细的答案。强调“更好的编译时间检查”这一点的价值。
NoChance 2011年

8
除了类型推断,还有Haskell样式的重载,C ++模板,泛型以及其他语言特性,它们提供了静态类型化框架中Duck类型化的某些优势-只要对象提供了所需的接口(它您可以使用“鸭子般的鸭子”),而几乎与该对象的标称类型无关。“几乎”是因为某些方法需要某种“这种类型的庸医,例如相关的鸭子”声明,例如Haskell中的“ class”声明。
Steve314

45
我必须非常不同意您的主张,即“较短的代码...更快地读取和维护”。有一个中间步骤,了解代码。我不得不在Delphi和JavaScript中都维护其他人的代码,而Delphi代码则更容易理解,因为它更冗长。尤其是因为Delphi代码具有类型声明,而JavaScript没有。当处理比原语更复杂的内容时,类型声明使您轻而易举地查看变量是什么以及变量可以做什么,这对于维护工作是必不可少的知识。
梅森惠勒

21
我不同意这里给出的大多数理由。以Haskell为例,它可能拥有最严格的类型系统。它具有REPL(实际上至少是两个),它通过对构造函数进行模式匹配而具有非常强大的多态性,并且它简明扼要-比Javascript或Python还要多。因此,我想您提到的某些原因是偶然的,而不是松散类型的语言所固有的。
安德里亚(Andrea)

15
我不会对“测试案例”过于信任。您无法将它们与好的类型系统进行比较。类型系统提供了一个证明,即至少已经使用类型正确的参数调用了您的函数,而测试用例只能提供经验证据。然而,即使是这种证据也是从人为的背景下收集的。
Ingo 2012年

56

使用动态语言,您可以比使用键入的语言更快地编写cr脚的代码。

快速创建大量动态内容后,您就可以安全地移至另一个项目,而无需担心长期维护。

这是生产力的提高:)

我在开玩笑,但是在参与了使用“动态语言”的项目后,如果想要拥有一个有效的产品,必须处理的大量不必要的测试,文档和约定让我感到恐惧。
并有很多在编译时可能会捕获到的运行时错误的喜悦。
哦,我也忘记了元编程让您在代码中引入的所有这些黑道和伏都教徒!

因此,对于中型/大型项目,在整个生命周期中提高生产率可能是一个神话。


11
是的,我的经历是一样的。一个100行的perl脚本是可以的,如果没有如此出色的工具,我们将会迷失方向。但是一个10万行的perl项目很可能是一场噩梦。
Ingo 2012年

3
...然后您有了JavaScript(不仅是动态的,而且是弱类型的)。
书斋

16

对于这个问题也有一个理论上的看法:静态类型系统本质上是一个专门的定理证明者,仅当它可以证明程序的类型正确性时才接受该程序。所有静态类型系统都拒绝某些有效程序,因为没有可判定的静态类型系统强大到足以证明所有可能的类型正确程序的能力。

有人可能会说那些不能由静态类型检查器证明的程序是骇客和/或不良样式,但是如果您已经有了一个有效的程序而类型检查器不接受它,那肯定会在短期内损害您的生产率。

在某些情况下,您可能会注意到类型检查器出现问题的情况是通用容器以及参数和返回类型的协方差/协方差。


18
相反,如果错误输入了错误的程序,则编译器会立即告诉您并突出显示错误的行。与注意到失败的测试运行和调试以发现错误相比,这可以提高您的生产率。
MarkJ 2011年

5
如果您做错了,通用容器和显式的协方差/“协方差”意在“挡路”。编译将在运行时失败的代码有什么好处?
M.Stramm

通常认为作业成功完成0%,直到它成功运行所有测试。只有这样,您的进步才算是无所不能。考虑到这一点,我认为在尚未完成的事情上衡量您的生产力是不值得的。
Pijusn 2013年

-1不能解决实际的问题(记住,“生产率提高”吗?)而且,您甚至可能不想编写那些“类型系统拒绝的有效程序”。仅仅因为可以做并不意味着你应该做。以及为什么您甚至会有类型检查器拒绝的“有效程序”?什么,您是在编写Javascript程序并突然尝试使其在Java中编译吗?
Andres F.

类型系统拒绝的那些有效程序可以帮助缩短代码,从而减少类型系统无法找出的错误(更少的代码=更少的错误)。可以使用带有测试值的动态语言(即REPL驱动的开发)来完成编译器/ IDE的突出显示这一行,因此您可以看到中间值,并且它们可以拾取类型系统无法实现的错误以及类型错误。您还可以使用静态类型推断来给您输入警告。
aoeu256

15

我发现大多数动态语言的一个优点是,它们使编写更通用的代码更加容易。当您不必为类型系统而战时,在更高的抽象级别上编写要容易得多。

您不必花太多时间去思考-编写对Java中的任何对象都不重要的事情的代码很困难,并且可能需要进行反射,而该反射基本上是动态类型的。使用JavaScript之类的东西,写一个对所有对象都做一些有趣的事情的功能是第二天性。一个完美的例子是我最近编写的一个函数,该函数接受一个对象并将其所有方法替换为既执行相同操作又触发事件的方法。我不知道如何用Java处理这种事情。但是,我不确定其中有多少是由于类型系统引起的,有多少是由于其他语言差异引起的。

但是,我最近开始使用Haskell。Haskell让我可以像使用过的任何动态类型化语言一样轻松地编写抽象的通用代码。我上面的Java / JavaScript示例在Haskell中没有任何意义,因为它没有对象,方法,事件甚至没有太多的变异,但是其他种类的通用代码确实很容易编写。

实际上,Haskell可以编写动态类型语言无法编写的一些通用代码;一个完美的例子是read函数,它与toString。您可以获取所需的an Int或a Double或任何类型(只要它在某个类型类中)。你甚至可以有多态性常数,因此maxBound可以最大IntDoubleChar...等等,所有这些都取决于什么类型的,它应该是。

我现在的理论是,与诸如Java之类的语言相比,使用动态语言所带来的生产力提高总是比它们的能力更低,更冗长且更不灵活。

但是,即使Haskell的类型系统也存在一些烦人的问题,而动态类型的语言则不会出现这种问题。我最烦恼的是数字的处理方式。例如,您必须弄乱类型系统才能将length(列表中的)类型用作双精度类型,如果没有类型系统,就不会有问题。我遇到的另一件烦人的事情是使用Word8期望的(无符号int类型)和函数Int

因此,最终,没有类型系统将使编写通用代码变得更加容易,而无需考虑太多,并且避免了讨厌的类型系统陷阱。您不必使用动态语言来对抗类型系统,但是您也不能依赖它。


1
是的,由于某些原因,数字系统很难正确设置。在斯卡拉,这也是一团糟。我认为动态类型系统在易于使用方面胜过简单的静态类型系统,但会从更高级的系统(例如Scala,Haskell,ML等,它们都使用system-F的变体)中输掉。
Edgar Klerks 2014年

3
您的回答很好,但有错误。首先,动态语言“没有类型系统”是不正确的,因此不能成为动态语言“使编写通用代码更容易”的原因。正如您自己对Haskell的反例所显示的那样,它们并没有使它变得更容易(您对自己的断言进行了揭穿!)。“您永远不必与类型系统抗争”是错误的:每次必须修复由静态类型检查不足引起的错误时,您都要与之抗争。最后,显式强制Int列表返回是很简单的。例如:1.0 + fromIntegral (length myList)即使用fromIntegral
Andres F.

2
最后,“快速编写代码”!=“提高生产力”。您的代码必须正常工作!如果编写的越野车软件以后必须花时间调试和修复,那么您的工作效率就不高。
Andres F.

对于大多数人而言,当他们谈论动态类型的语言“提高生产力”时,“无需过多考虑”
危险信号

如果类型系统确实提高了生产率,那么Haskell或Idris中所有有用的应用程序在哪里?我认为,理解类型错误有多么容易,“可补丁性”(以不可预测的方式编辑应用程序的能力)以及doctest和类型推断的90%错误检查等事情可能更为重要。
aoeu256

7

问:我经常听到有人说动态类型的语言比静态类型的语言生产力更高。提出索赔的原因是什么?

这有历史原因。如果回溯几十年,动态语言无疑比静态语言生产力要高得多(同时速度也要慢得多)。如果您同时知道Perl和Perl,那么Perl显然比C生产率高得多。但是随着时间的流逝,语言之间已经相互借鉴了很多,更新的语言正在缩小两者之间的差距(在生产率和性能方面)。

这里有几点要考虑:

垃圾收集:垃圾收集极大地提高了生产力。我相信Java是GC的第一种主流静态语言。在此之前,静态基本上意味着手动内存管理。(注意:在这里和以下内容中,我仅考虑主流语言。存在​​许多实验性和特殊语言,它们将为我提出的任何观点提供反例。)

内存安全性:这是生产力的提高,您不必担心用脚射击。在使用诸如Java之类的“托管”静态语言之前,静态通常意味着直接内存访问。调试也是生产力的一部分,不安全的内存访问会导致真正难以理解的错误。

繁琐的类型系统。在以静态语言引入参数化类型(如模板或泛型)之前,静态类型系统的局限性通常是一个负担。例如,在Java中,每次从集合中选择一个项目时,您都必须显式地向下转换。因此,您获得了强制转换的语法开销,并且没有类型安全性。考虑到编程中集合的普遍性,这是一个主要缺点。
必须声明所有内容的类型是很多冗余类型,但是通过现代类型推断,可以显着减少这种类型。

大标准库。由于大型标准库,Python被著名地宣传为“包含电池”。与具有极简标准库的C相比。但是,随着Java和.net等平台的出现,庞大的标准库正在成为标准,而Scala和F#等较新的语言正在“免费”继承此库。

一流的数据结构。诸如Perl和Python之类的动态语言具有内置的一流数据结构(如列表和映射),以及用于常规操作的便捷语法捷径。与此相比,C除了固定大小的数组外没有内置集合。

闭包和lambda语法 -动态语言通常从一开始就具有这种功能,但是静态语言采用了这种语言,最近才采用Java。

REPL具有以交互方式快速测试代码段的能力是一个很大的福音。但是,尽管使用了IDE工具,例如Visual Studio中的“立即”窗口,但是静态语言可以在某种程度上模拟它。

先进的工具 -除了上述静态语言越来越接近动态语言的便利性之外,现代编辑人员还以动态语言难以匹配的方式利用静态分析。例如,编辑人员可以提供安全的自动重构功能,这在动态语言中是严格不可能实现的。

底线:历史上确实如此,但是今天的答案还不那么明确。


问:那么,对于动态类型的生产力而言,这到底是类型模型本身的优势呢?

很难将动态类型化模型与动态语言区分开来,但是作为示例,C#随着时间的流逝采用了更多的动态特性,即使它的核心是静态语言。这确实是动态类型模型的好处的证明。例子:

反思 反思从根本上说是一种动态打字功能。您可以在运行时评估程序而非编译时检查对象类型。引入它时,人们对此并不满意,但是在C#中,反射的使用变得越来越普遍,例如ASP.Net MVC大量使用反射。

属性 属性是动态类型化的一个示例。您可以在编译时向类添加任意属性,然后在运行时检查(通过反射)并基于该对象操作对象。诸如MEP之类的东西基本上是基于动态类型模型的扩展框架。

Linq to SQL,EF mv。 各种Linq转换器将查询作为运行时对象进行检查,并即时生成sql。它没有比在运行时检查代码更动态。CodeDom是硬币的另一面,可以在运行时生成代码

Roslyn Roslyn基本实现eval,曾经被认为是一种真正的动态语言的定义特征。

动态dynamic型是在C#中最明确的动态特征,并使得外部物体和简单和更富有成效的语言交互广告。但是为了方便起见,它也用于Asp.net MVC中。

所有上述特征的好处表明,即使在具有参数化类型,结构类型和类型推断的静态语言中,动态模型也具有明显的优势。


我真的不喜欢这个答案,因为几乎所有要点都没有解决核心问题,即“动态键入应该带来多少生产力?” 不是动态语言
保姆2015年

@nanny您能详细说明一下动态类型化语言与动态语言之间的差异吗?(其模糊事物之一)。您能否举一个不是动态语言的动态类型化语言的示例,并给出每种语言的明确定义?

@nanny:这个问题实际上是关于“动态类型化语言”的,而不仅仅是“动态类型化”。
JacquesB 2015年

@MichaelT对不起,我不清楚。动态类型化是所有动态语言的一方面。这个答案是在谈论其他方面,从历史上看,动态语言往往会伴随而来,而实际上并未涉及动态打字部分。
保姆

1
@nanny:我基本上是在回答这个问题:“我经常听到这样的说法:动态类型的语言比静态类型的语言更有生产力。产生这种说法的原因是什么?” -我相信提出这一要求的原因是历史性的,不仅与动态类型有关,而且与动态语言的其他提高生产率的功能有关。
JacquesB 2015年

6

所有现代语言功能的整体是如此之大,以至于静态和动态类型都不占很大的分量。

规则是,语言功能越好,代码越短。那很简单。Java展示了静态类型输入如何严重错误,这给对手带来了很多麻烦。设计不良的语言功能通常要付出代价,而Java中的静态类型首先是必需的功能(否则,大多数人甚至可能不会使用它),其次是执行不力。
相比之下,这就是为什么大多数动态语言都闪耀的原因,尽管我会认为PHP并不能真正使您的生活总体上更好(至少直到最近),因为其他许多与类型系统无关的怪癖。

另一方面,您有很多具有表达类型系统的语言不会妨碍您,甚至不是强制性的。每当您需要对类型系统进行转义时,其中的一些甚至还允许嵌入未类型化的代码。

就我个人而言,我使用haXe,这是一种具有类型推断功能的语言,包括名义和结构子类型,可选的非类型化代码,一流的函数类型,代数数据类型以及(不是很成熟但功能非常强大的)词法宏,同时避免了奥秘的语法。在使用haXe大约3年之后,我得出一个简单的结论:

当您的语言不会让您陷入关于范式的宗教选择中,而只是成为一个好工具时,编程就变得容易得多。有许多静态和动态语言以及混合语言可以成功地做到这一点。其中一些很容易学习,最难掌握。
它们的强大功能来自于其各个特征的组合方式,可以轻松地为复杂问题创建简单的解决方案。这排除了一定的正交性,只有通过对到目前为止探索的所有语言功能进行包含或省略的微妙平衡才能实现。如果您尝试向Ruby添加静态类型,则会削弱它,如果您尝试将其从Haskell中删除,则会对其进行粉碎。与此相反:如果您将它从C那里拿走,人们几乎不会注意到;如果您从Java那里把它拿走,有些人可能会感谢您。

从我的亲身经历,我可以告诉你这一点:我喜欢Ruby。它拓宽了我的视野和设计系统的方式。恕我直言,它应该首先用来教人们编程。它不显眼,功能强大,简洁,有趣。我了解为什么来自正统语言的人会喜欢它。
但是从长远来看,静态类型允许将工作推迟到静态分析器中进行,并且通过类型推断,这基本上是免费的。结果是易于维护且通常运行速度更快的代码。

但同样,仅静态类型无法完成任何工作。这是结合的问题。我认为在F#,Scala,Nemerle,OCaml或haXe之间,您可以找到自己的最佳选择。但这最终取决于您,因为该语言应允许您毫不费力地嵌入自己的思想,而不是强迫您将思想转弯。毕竟,如果编程很有趣,那么没有什么比生产率更高。


“规则是,语言功能越好,代码越短。” 在某种程度上,这可能取决于意见,但我认为此说法不正确。较短的代码本身并不能提供太多优势,除了在写入时减少键入内容,而且可能占用更少的磁盘空间(无论如何,这在编译语言中也不是问题)。我认为,一种好语言的印记正在以尽可能简洁的方式传达尽可能多的信息。动态类型化不是非常自我记录,并且因此失去了可维护性imo
Ataraxia

您可以在动态类型化代码中添加以下信息:默认值/关键字参数,从类型推断中获得的类型,从JIT编译器中进行动态类型推断,或者仅记录所有函数[遍历正在运行的程序中的每个函数或类,然后将其替换为记录参数/结果的函数版本)。然后,您可以查看该函数先前运行的日志。另一个想法是拒绝既没有类型注释,运行时协定也没有示例REPL会话测试的代码,但使开发人员可以选择这三种代码中的任何一种。
aoeu256

3

就个人而言,动态键入会有所帮助的唯一原因是,如果您是一位非常慢的打字员,或者您构建了庞大的功能/方法/难以导航的内容。您还必须解决整个单元测试问题。动态类型需要(除非您喜欢编写残破的代码)剧烈的单元测试(以确保您的动态类型不会意外爆炸(即,变量主要是鸭子,但有时偶然是dcuk))。静态方法将更加努力地防止这种情况的发生(是的,您可以为进行严格的单元测试提供参数)


0

我认为首先您需要定义“生产力”。“生产力”是什么意思和包括什么?

如果说“提高生产力”是指编写更少的代码行来实现相同的功能,那么可以,动态类型编程语言比静态类型语言更“高效”。

但是,如果您还考虑花费在调试和错误修复上的时间,那么动态类型化的语言可能没有那么高效,因为动态类型化的语言倾向于将错误检查推到运行时,而静态类型化的语言则相反。可以在编译时执行一些错误检查。众所周知,通常,发现错误的时间越晚,修复该错误的成本就越高。因此,与静态键入代码相比,动态键入代码可能会导致生产率总体上相等或更低。


通常,使用动态语言可以用更少的行编写功能并非正确。您正在比较哪些语言?
Andres F.

@AndresF。哦,我主要使用Python和C ++。
yaobin

1
好的,但是当您实际比较Python和C ++时,您不能概括动态与静态。C ++并不是具有静态类型的语言的特别具有代表性的示例。有非常简洁的静态类型语言,这些语言或多或少允许您编写与Python一样简短的程序。因此,通常来说,您的主张是错误的。
Andres F.

是的,但是如果您在程序仍在运行时对其进行编辑,该怎么办?任何运行时问题都只会发生,您可以在此修复它们。在Lisp中,每当遇到错误时,您都可以修复程序,然后继续运行它...是的,对于更复杂的路径,类型注释会很好[也许您可以使用像mypy和lisp这样的渐进式输入],但是那些更复杂的路径也可能会出现非类型错误,因此避免使用任何语言的复杂路径都是一个好主意。
aoeu256

-1

动态键入的最大优点是生产率。

Python,Ruby等除了动态类型(默认参数,内置类型的字典等)以外,还具有许多其他提高生产力的作用,对程序员生产力的累积影响是令人印象深刻的。

在速度(或缺乏速度)和资源消耗方面的惩罚并没有您期望的那么糟糕,并且在大多数情况下,开发速度和灵活性可以弥补这些损失。

有一个(很老!)放在这里的主题。这是对程序员生产力进行的为数不多的适当研究之一,许多结论仍然有效。

今天可能要进行的研究(可能)不同:

  1. Java JVM的改进令人难以置信。
  2. 现代的IDE可以提高C ++和Java编码器的生产率,但是对脚本语言的影响很小。
  3. C#将被包括在内,可能与Java处于同一个领域,但略胜一筹。

因此,传达的信息是,除非性能是一个非常严重的问题,否则动态语言将提高您的生产率。


2
我不清楚动态键入究竟能提高您的生产率。这篇文章很有趣,但是它是关于一个非常小的程序的,我不确定这如何在大多数程序中延续到成千上万行代码。
汉斯·彼得·斯托尔2011年

5
该研究仅使用C,C ++和Java作为静态语言的示例,然后尝试将发现的结论总体上应用于传统编程语言。三种语言都具有相同的基本语法,但具有相同的固有的,降低产品性能的缺陷,从而使比较无效。并不是说静态语言没有生产力,而是C族没有生产力。 如果他们在测试中加入了Pascal方言,他们很可能得出了不同的结论。
梅森惠勒

@mason-在该领域中很少有实际的客观研究。这是少数具有实际数字等的真实研究之一。“样本”程序并不简单!它结合了字典处理,复杂算法和大数据量的元素。失败和崩溃尝试的高百分比证实了该任务的重要性。
詹姆斯·安德森

2
-1关于如何使动态类型的语言更具生产力,您并未说太多。默认参数和字典可以在静态类型的语言(例如Scala)中找到。
乔纳斯(Jonas)

1
@JamesAnderson更糟糕的是,您链接到的论文甚至都不支持您的观点。它将“脚本语言”(通常为动态)与“ 常规语言”(通常为静态)进行比较。现在,告诉我,“传统”语言到底什么?您认为它与具有静态类型的语言集相同吗?更糟的是,纸张不老。到2000年,已经有很多具有静态类型的出色语言,可以说比动态语言生产力更高。
Andres F.
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.