it-swarm.cn

静态类型值得权衡吗?

我开始在Python主要是在没有类型安全的地方进行编码,然后移到C#和Java在那里。使用Python可以更快,更轻松地解决问题,但是再说一次,我的C#和Java应用程序的复杂程度要高得多,所以我从未给出Python我想是真正的压力测试。

Java和C#阵营听起来好像没有适当的类型安全性,大多数人会碰到各种可怕的错误,这比它的价值还要麻烦。

这不是语言比较,因此请不要解决编译与解释之类的问题。 类型安全性值得发展速度和灵活性吗?为什么?

对于想要举例说明动态键入更快的人:

“在开发过程中使用动态类型的语言。它可以为您提供更快的反馈,周转时间和开发速度。” - http://blog.jayway.com/2010/04/14/static-typing-is-the-root-of-all-evil/

110
Morgan Herlocker

程序员不必担心动态类型语言中的类型是一种神话。

在动态类型语言中:

  • 您仍然必须知道您是否正在使用数组,整数,字符串,哈希表,函数引用,字典,对象或其他任何东西。

  • 如果是对象,则必须知道它属于哪个类。

  • 将这些类型之一分配给预期为另一种类型的变量或函数参数几乎总是错误。

  • 在较低级别上,例如,如果要填充TCP)数据包,则必须经常考虑位数或有符号与无符号的比较。

  • 您可能会遇到问题,在您真正想要一个空字符串的地方得到零。换句话说,您仍在调试类型不匹配的错误。唯一真正的区别是编译器没有捕获错误。

  • 我认为您什至没有节省太多的键入-,因为您倾向于在注释中记录函数参数的类型,而不是在代码中对其进行记录。这就是为什么doxygen样式的注释块在整个动态类型代码中在实践中更为流行的原因,在静态类型语言中,您通常只在库中看到它们。

这并不是说使用动态类型语言进行编程不会感觉更令人愉悦,因为编译器并不总是在您的支持下,而经验丰富的程序员不会往往很难找到并纠正静态类型仍然会捕获的错误类型,但这与所谓的效率提高或错误率降低是完全不同的问题,对于动态类型,即使是静态类型也最多。

164
Karl Bielefeldt

随着类型变得更强大,它们可以为您提供更多帮助if您可以正确使用它们而不是与之抗争。设计类型以反映您的问题空间,逻辑错误更有可能成为编译时类型不匹配,而不是运行时崩溃或无意义的结果。

124
geekosaur

免责声明:我是类型爱人;)

您的问题很难回答:那是什么权衡

我举一个极端的例子:Haskell,它是静态类型的。实际上,也许是存在的类型最强的语言之一。

但是,Haskell支持Generic Programming,在某种意义上,您编写的方法可以使用符合特定概念(或接口)的任何类型的方法。

此外,Haskell使用类型推断,因此您不必声明变量的类型。它们是在编译期间静态计算的,就像Python解释程序会在运行程序时计算它们一样。

我发现大多数对静态类型苛刻的人实际上是在抱怨其他东西(冗长,将一种类型转换为另一种类型的痛苦),但是在进行静态类型化时,Haskell没有任何这些问题…….


简洁的例子:

-- type
factorial :: Integer -> Integer

-- using recursion
factorial 0 = 1
factorial n = n * factorial (n - 1)

除了内置的支持,很难简明扼要。

通用编程示例:

> reverse "hell­o" -- Strings are list of Char in Haskell
=> "olleh"
> reverse [1, 2, 3, 4, 5]
=> [5,4,3,2,1]

类型推断示例:

> :t rever­se "hell­o"
:: [Char]

可以简单地计算出:

  • "hello"Char的列表(表示为[Char]
  • reverse应用于类型[A]返回类型[A]

尝试一下 在您的浏览器中

78
Matthieu M.

我喜欢静态类型的语言和动态类型的语言。对我来说,类型安全的两个最大优点是:

1)您通常可以从函数的类型签名中完全推断出它的功能(在诸如Haskell之类的功能语言中尤其如此)。

2)当您进行重大重构时,编译器会自动告诉您为使一切正常运行而必须做的一切。当我在C++中重构某些内容时,我的过程通常很简单:a)更改我知道要更改的部分,然后b)修复每个编译错误。

37
dfan

就个人而言,我发现类型安全有助于我在当前工作中更快地发展。几乎在键入时,编译器会为我做很多检查,从而使我可以将更多精力放在正在实现的业务逻辑上。

对于我来说,最重要的是,尽管我失去了一些灵活性,但我获得了一些时间,而这些时间本可以花在跟踪类型问题上。

29
Michael K

类型安全是否值得在开发速度和灵活性上受到打击?

因此,这实际上取决于您在做什么。如果您正在编程,例如飞机的备用系统,则类型安全可能是解决之道。

动态语言与静态语言编程实际上是两种不同的动物。他们俩都需要一个根本不同的方法。您通常可以在静态和动态之间移植一种方法,但是您会失去其他方法的优势。

这真的是一种心态。这个比那个好吗?这实际上取决于您是谁以及您的想法。我与之共事的大多数人即使不需要也不会接触动态语言,因为他们觉得错误的余地很大。他们认为这是错误的吗?不,当然不是,但这确实意味着他们已经意识到,在动态环境中无法应用其编码风格的方法。我和用户组一起去的其他人则完全相反。他们发现静态类型太麻烦了,因为它限制了他们解决某些类型问题的方法。

老实说,我经常在JavaScript和C#之间切换。现在,了解和使用两种语言确实会在某种程度上影响另一种语言,但实际上,我用两种语言编写的代码看起来完全不同。它们需要不同的方法,因为它们根本不同。我发现,如果您发现自己在想“用X语言来做这件事要困难得多”,那么您的方法可能会有点偏离。这是一个例子,人们谈论“ Pythonic”的做事方式。这意味着Python)语言可以使问题更容易解决。采用其他方法通常更困难,也更麻烦。您必须克服认识的难题语言的工作方式对您真正有用。动态语言与静态语言完全一样。

12
kemiller2002

最近有一个类似的问题问: 网站的动态语言和静态语言

重申我的回答的核心:

随着系统的变大,静态类型语言可确保组件级别的鲁棒性,从而确保系统级别的灵活性。

是的,Java是严格键入的,是的,Java很烂(没有冒犯。它很棒。伟大的平台和生态系统,但是有史以来最糟糕的语言之一(实际上正在使用))。
但是,由此推断,严格键入很糟糕。这就像指向PHP并推断动态类型很烂(再次,没有冒犯之处。它正在慢慢改善,我给您提供))。

就我个人而言,我的大部分开发工作都是在 haXe 中进行的,它具有静态类型系统。它不仅比Java)更具表达力,而且由于类型推断而需要的工作量更少,但它也是可选的。如果它妨碍了您,您只需绕开它。

类型安全是一项功能(这是许多所谓的高级语言所不具备的功能)可帮助您防止自己被人用脚射击
而且,如果您选择随意检查代码类型,那么对于任何成功的动态类型语言来说,都会更好。
例如,我当然喜欢Ruby,但那主要是因为Ruby完全面向对象,与编译时类型系统完全正交。

我认为,静态类型系统具有吸引力的说法仅基于缺乏良好的静态类型系统的知识。有很多语言可以做到这一点,其中之一就是语言,而且在这方面甚至还不是最好的。

HaXe代码示例:

class Car {
    public function new();
    public function wroom() trace('wroooooooom!')
}
class Duck {
    public function new();
    public function quack(at) trace('quackquack, ' + at + '!')
}

function letQuack(o) o.quack();
letQuack(new Car());
letQuack(new Duck());

这将产生一个编译时错误:

Car should be { quack : Void -> Unknown<0> }
Car has no field quack
For function argument 'o'
Duck should be { quack : Void -> Unknown<0> }
Invalid type for field quack :
to : String -> Void should be Void -> Unknown<0>
For function argument 'o'

您不能真正声称我必须在类型安全性上付出很多努力。

说您不需要类型安全性,因为您已经进行了测试,这更加愚蠢。编写测试很无聊且重复。而且我真的不想写测试,只是为了发现Car实例不会发出嘎嘎声,而Duck则需要有人来发出嘎嘎声。

归根结底,无论开销成本多少,您都会发现它最终被摊销了(即使Java-尽管可能不会很快))。

7
back2dos

这取决于。

人为故障模式通常是统计性的。强类型检查减少了某些特定类型的人为错误(导致错误代码)的可能性。但是仅仅因为你会失败并不总是意味着你会失败(墨菲无法承受)。

减少潜在故障几率是否值得付出代价,这取决于。

如果您正在为核电站或ATC系统编写代码,那么减少人为故障模式可能是极端重要。如果您正在快速制作一些没有规格且故障后果几乎为零的网站创意,那么减少故障模式或概率可能会或可能不会给您带来任何好处,但可能会花费您大量的开发时间(更多按键操作等),并通过记住当前所需的类型来分散大脑细胞的注意力。

5
hotpaw2

无论出于何种原因,我都不会再犯与经常发生的对象类型有关的错误。在C#之类的语言中,与发生运行时强制类型转换相比,我更可能犯错误,而不是可能产生编译器可检测到的类型安全性错误,我同意,这通常是由偶尔需要解决静态问题引起的。输入语言。当我编写Ruby时,代码倾向于强烈地暗示对象的类型,并且REPL的可用性意味着我已经通过实验验证了所需的方法/属性是否存在,或者我将进行基本相同的单元测试,因此我也很少遇到Ruby中的类型安全问题。

但这并不是说静态类型的系统不能比它们更好。

在静态类型语言中,system类型实际上也很重要。例如,使用功能语言中的Some Somead(type <Some>:= yes x | no)之类的东西,您将获得编译时检查,这些检查从本质上防止了大多数类型系统中常见的可怕的NullReferenceException异常。当模式匹配代码运行时,您会收到编译时错误,告诉您无法处理null条件(如果使用该机制声明类型)。在F#中使用|>管道运算符之类的东西时,还可以减少类似类型的错误。

在Hindley-Milner的静态类型传统中,您可以构建的东西不仅仅可以保证类型声明支持接口X,而且一旦有了这些东西,我就会说静态类型的系统将变得很多更有价值。

如果不是这种选择,则C#的按合同设计扩展可以添加另一组机制来增加静态类型系统的价值,但与某些功能范式相比,它们仍然需要更多的约束。

5
JasonTrue

类型是接口上的约束,因此它们是您可能要使用单元测试进行测试的子集,因此,许多折衷方案相似:

  • 静态类型会提供有关代码是否满足类型系统可以表达的要求的较早反馈,以换取延迟构建功能最少的东西的反馈(例如客户反馈或更高级别的测试)。
  • 知道代码满足某些要求可以简化重构和调试,但同时也会增加更改接口和更改要求的开销。
  • 尤其是如果静态类型的语言缺乏强制性,则它可以提供更高的安全性,以防止在代码上使用会导致错误的代码(减少对条件和断言的需求),但是过于严格的约束要求用户编写更多代码以将其数据压缩到可接受的形式(例如显式类型转换)。
  • 显式类型注释可以帮助理解阅读代码的过程,也可以使带有多余或不必要信息的代码混乱。
  • 根据实现方式,它可能会降低简洁性。这取决于诸如是否需要类型注释或推断类型注释,类型系统可以如何很好地表达泛型类型/接口,语法以及是否要测试类型系统可以表达的约束(例如,同一测试作为语言功能比作为单元测试可能更简洁,但是您可能没有打算对其进行测试)。
  • 另外(与TDD不相关),静态类型可以帮助优化编译时间,但需要进行类型检查(并花一些时间检查它们并执行优化),而如果将数据限制为类型,则可以进行更好的优化可以很好地映射到硬件。这简化了对具有性能要求的代码的开发,但是可能会导致无法很好地满足这些约束的代码出现问题(按照第3点)。

总而言之,我认为动态语言对于原型制作特别有用,而如果您需要确保代码正确,则应该使用强类型系统。

4
T.R.

当然是。当您同时使用强类型语言和Python(Python是强类型)时,您会发现的一件事是,动态语言中大多数编写良好的代码无论如何都倾向于遵循许多与强类型代码相同的约定。动态类型对于序列化和反序列化非常有用,但是对于大多数其他事情,它实际上并没有带来太多优势。除非您的大多数代码与序列化有关,否则为什么要放弃免费的错误检查?

3
Mason Wheeler

摩根,我为您提供了一个有趣的主意:静态+动态输入。您提到了Python,C#和Java。您知道吗,.NET和Java都有Python)的相当不错的端口?在两种情况下,端口都可以让您使用这些平台的库和/或与现有代码互操作。这给您几种可能性:

  1. 将旧代码以静态,僵化的语言保留。使用Python用于新内容。
  2. 使用Python)在成熟平台之上对新事物进行原型设计。以更成熟的语言重新编码要保留的组件。
  3. 对经常更改的部分使用动态语言。
  4. 可能使用动态语言来处理诸如修改运行代码之类的想法。
  5. 除了使用强类型语言的关键部分以外,还应使用动态语言进行所有操作。

我早在90年代末就使用这些方法来解决C/C++开发的痛苦。我需要本机库,有时还需要性能。但是,我想要更好的语法,灵活性,安全性等。因此,诀窍是仔细地将它们组合在一起以取得正确的权衡。在实践中,通常比将整个语言和旧代码扔掉为另一种语言/平台更好。

(注意:一个答案已经说过了,但是我也想再次强调动态类型!=否/弱类型。许多动态类型系统在内部使用强类型。我思考产生类型动态的方式是:变量类型在运行时确定,不需要类型注释,并且/或者可能在运行时更改。

3
Nick P

有很多用LISP编写的非常复杂的系统,而且我还没有听到任何Lisper抱怨他们希望使用静态类型。当我使用它时,我不记得有什么问题使我感到无法适应静态类型系统(您可以在Common LISP中静态指定类型)的速度。

而且,主流的静态类型语言似乎不太适合捕获错误。在设计布局时,重要的是一定数量是页面上的垂直尺寸,而不是intunsignedfloatdouble。另一方面,编译器通常会标记它认为不安全的类型转换,并且很高兴让我添加垂直度量和字符串中的字符数。静态类型系统的这种弱点是西蒙尼(Simonyi)匈牙利概念背后的初衷,后来被混为丑陋的无用之举。

3
David Thornley

我看到这个问题很多,并且我认为您的软件质量(以及缺少错误)与您的开发过程,系统的体系结构以及您和您的同僚对代码质量的承诺有更多关系。

我的上一份工作主要是python开发。我在一家大型的国际网络托管公司工作,我们在美国,加拿大和韩国拥有开发团队。Custom python前端客户应用程序的Web框架,允许用户管理其域名和Web托管帐户。后端:全部python也。Python web在我当前的工作中,客户端应用程序全部使用Java;我们的主要产品是Java和flash。自定义Java我们较旧的应用程序的Web框架,较新的内部工具的wicket。

在两个方面都工作过之后,我不得不说每次看到这个问题都会困扰我。如果您使用的是动态类型的语言并实际测试您的代码,那么您会很好的。如果系统设计合理,并且您遵循标准,那么您会没事的。由于没有编译器检查类型,因此不会出现很多错误。大多数错误都是逻辑错误,就像我的Java今天的工作。

2
LGriffel

类型安全是否值得在开发速度和灵活性方面受到打击?为什么?

静态类型是软件整个生命周期中开发速度和灵活性的净值增加。它减少了总的工作量和不便之处,但将大量的工作量和不便之处提前转移了,这一点更加明显。拥有有效代码的入门门槛更高,但是一旦您克服了这一障碍(通过满足类型检查器的要求),扩展和维护该代码就可以减少工作量。

由于以下原因,软件开发中总是会有些头疼:

  • 您想要完成的工作固有的复杂性

  • 人类固有的易失性,尤其是考虑到当我们尝试做更复杂的事情时我们犯了更多的错误

迟早,您需要花一些时间来解决这些挑战。没有解决的办法。静态类型化只是早日解决了这些挑战,而不是日后解决。越早越好,因为您发现错误的时间越晚(不是if的问题,而是when的问题),则纠正该错误的成本就越高。

纠正类型检查器报告的错误所花费的成本要比调试运行时引发的与类型相关的异常所花费的成本低得多。将类型检查推迟到运行时仅仅是解决问题的方法。

2
Jordan

您不会得到一个真正客观的答案,但是我的经验是类型安全是无价之宝直到您掌握了TDD。一旦进行了大量的单元测试,并且测试是在代码之前编写的,那么检查编译器就很麻烦了,实际上开始妨碍您了。

2
pdr

是。

我曾在PHP应用程序,其中类型不像Java或C#。)那样强。为了避免错误的自动转换或验证数据。

动态类型语言对O.S有好处。脚本和快速的小型应用。而不是复杂的应用。

摘要:如果必须为复杂的业务应用程序选择“弱类型”或“动态类型”编程语言,还是“强类型”编程语言,则选择“强类型”编程语言

0
umlcat

我认为应该退后一步,考虑一下动态类型何时会引起问题。

一种情况是根本不测试代码分支,但是坦率地说,无论是否使用动态类型,从未测试过的代码都可能有问题。

另一个更微妙的问题是可替代性不完善。

如果类型是完全错误的,则除非从未使用过特定的代码路径,否则很可能会很快检测到该路径。

另一方面,如果类型不能完美替代,则代码通常可以正常工作,但会以细微的方式中断,直到很久以后才会被发现。

编程中最常见的两种类型是数字和字符串。在许多动态语言中,它们是彼此的不完美替代。用javascript或php表示,如果您提供期望字符串的数字,反之亦然,则您的程序运行时不会引发错误,但可能以相当巧妙的方式表现不佳。

Python避免了这个特殊的问题,数字和字符串在任何情况下都无法替代,并且在预期会使用另一个的情况下尝试使用它们通常会导致快速失败。

但是,它并不能完全避免不完全的可替代性问题。不同类型的数字可能无法完美替代,所以不同类型的序列也可能不完美。


我要说的是,我认为不可能以通用的方式比较静态和动态类型的收益和成本,因为我认为收益和成本都取决于语言的静态或动态类型的特定变化。用途。

0
Peter Green

这只是我自己的观点,但是不,我认为类型安全性不值得。一秒钟都没有。

我已经很长时间了。从c ++,c#开始,然后移至javascript(通过node.js进行前端和后端)。自从我使用JavaScript进行开发以来,我的工作效率飞速攀升,以至于我实际上使用基于类型的语言会使我的工作变得更糟。我也反对编译,我希望现在一切都在运行时。口译语言确实是我发现自己喜欢编程的地方。

至于类型,我只是看不到任何好处。我现在看到类型与查看内存管理相同。完全没有必要。明天的语言应该完全使开发人员不了解类型。计算机应该理解类型,而使开发人员远离它。

这是一个例子。我只是在使用Swift(Apple的新语言),希望它实际上能在一天前达到其名称,并尝试这样做:var n = 1/2无效。就像,这是怎么回事,然后可悲的是我意识到我必须做var n:Float = 1/2。这让我想起了我讨厌类型系统多少,以及它们不必要的恶化。

我什至不敢说我什至不希望用户定义的类型(例如Classs)。我根本不需要类型。我想要的只是var和objects。任何对象都可以用作任何对象的地方。对象是动态的并且不断变化。关于什么有效和什么无效的问题成为运行时问题。

开发人员喜欢说松散类型的语言对大型项目不利。但是我会说相反。对于大型项目,强类型语言是可怕的。如果您说JavaScript无法在大型项目中使用,请向Uber咨询一家规模超过400亿美元的公司,该公司在node.js/javascript或以PHP开头的Facebook上运行所有后端。

就静态类型语言而言,它不利于当今的快速迭代。这是一个简单的示例,您有10个开发人员使用持续集成服务器来处理.net项目,一个开发人员提交了一个错误,整个构建都被破坏了,即使这10个开发人员正在做不同的事情,他们现在都已停止并等待让有问题的开发人员纠正错误。谈高效吧?类型系统/静态语言以这种方式相互依赖,并使您的代码相互依赖。但是,脚本文件从不相互依赖。如果其中一个脚本有问题,它不会停止生产,那么您看到的所有问题都将留给运行时。而且运行时永远不会停止。永不中断。它可能会产生错误的输出,但不仅会像类型系统那样停止整个过程。

0
user19718