静态类型值得权衡吗?


108

我主要是在没有类型安全性的地方开始使用Python进行编码,然后转移到存在C#和Java的地方。我发现我可以用Python更快地工作并且减轻头痛,但是再说一次,我的C#和Java应用程序的复杂性要高得多,所以我从未想过要对Python进行真正的压力测试。

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

这不是语言比较,因此请不要解决编译与解释之类的问题。类型安全是否值得在开发速度和灵活性方面受到打击?为什么?

对于想要一个例子的人来说,动态打字速度更快:

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


15
这个问题与“ 支持弱类型化的参数有哪些 ”相反
妮可(Nicole)

8
@Prof Plum:我是否需要证明开发速度和灵活性受到打击?由于我们在谈论Type Safety的特定方面,使用Java还是C#不确定,所以他们提供它的方式并不是唯一的...
Matthieu M.11

32
使用严格的语言进行努力,您可以最大程度地减少“头痛”,然后甚至可能由于IDE自动完成,代码生成和代码提示而导致速度提高
妮可(Nicole)

9
@Prof Plum:我了解,我不希望您(或任何真正的人)全面测试过曾经创建的每种语言^^问题是,我见过的大多数人都在抱怨编程语言的某些特定方面(静态通常会出现键入)通常抱怨某个特定的实现,而没有意识到这一点。
Matthieu M.

5
@Prof Plum,博客文章中关于速度的所有实际要说的是一个秃头断言:“任何使用Ruby或Smalltalk等现代动态类型化语言进行认真工作的人都知道,它们效率更高。” 实际上,没有实际的例子说明它如何使开发更快。
Carson63000 2011年

Answers:


162

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

在动态类型语言中:

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

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

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

  • 在较低的级别上,例如,如果要填充TCP数据包,则仍必须考虑位数或有符号数与无符号数之类的问题。

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

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

这并不是说使用动态类型语言进行编程不会让人感到愉快,因为编译器并不总是在您的支持下,而且经验丰富的程序员也不会发现并纠正静态类型无论如何都会遇到的错误类型,但这与所谓的效率提高或错误率降低是一个完全独立的问题,对于这种情况,即使是静态类型,动态类型也最多。


10
我将不得不对经验丰富的程序员不制作/引入此类错误的观点提出质疑。谦虚并承认自己可能犯错误的优秀开发人员(而经验丰富的开发人员并不总是这样),则不太可能创建这些错误。
杰伊·杰伊

12
我完全不同意“我认为您什至没有节省太多打字”。您最终会在注释中记录类型并在测试中进行检查,如果有的话,则需要更多的输入和维护(毕竟,只要类型发生更改,您就必须记住要更新所说的注释,而且通常不会)。
Severyn Kozak

与在冗长的静态类型语言(如C#或Java)上节省下来的时间相比,我们在Python商店记录类型上花费的时间要多得多。还值得注意的是,像Go和Rust这样的新一代语言都使用类型推断,因此您输入的是“ x:= new(Object)”而不是“ Object x = new Object()”。
weberc2

当您说动态语言让您感到更愉快时,我同意您的看法,但我不知道为什么。您对此有解释吗?
罗德里戈·鲁伊斯

是的,您无需使用变量的类型,而可以在Python中使用默认值或单元测试(内联doctest)。同样在Python中,有时会出现拼写错误的怪异错误(如果您使用自动完成功能,这种情况发生的可能性较小,尽管在动态语言中并非总是如此,但通常可以使用自动完成功能),并且必须弄清楚self.bread = 5是否正在引入面包或重新定义它。
aoeu256

123

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


37
+1!“逻辑错误更有可能变成编译时类型不匹配,而不是运行时崩溃或无意义的结果”:确实是个好答案!当我花更多时间设计类型时,代码会更自然地遵循,并且通常在编译后就正确了。设计类型意味着理解域及其操作。
乔治

78

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

您的问题很难回答:这些折衷是什么?

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

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

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

我发现大多数对静态类型苛刻的人实际上是在抱怨其他东西(冗长,为改用另一种类型而痛苦),但是在进行静态类型化时,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]

在浏览器中尝试一下


4
为了扮演魔鬼的拥护者,在动态语言方面(至少在原型设计时),需要进行权衡取舍,就是只要类型声明可以起到与某些单元测试相同的作用,它们还可以以与单元测试相同的方式巩固接口(虽然肯定会减少开销)。同样,没有强制性的静态类型语言虽然更安全,但需要显式类型转换(尤其是当类型不够通用时),这可能会降低简洁性。
TR

7
我不知道Haskell,但为+1表示“实际上是在抱怨别的东西(冗长,为改用另一种而感到痛苦)”
妮可(Nicole

1
@Aidan:Haskell是一种不断发展的语言。Haskell 98是对Haskell 1.4的改进。Haskell 2010是对此的改进。同时,值得注意的是,对于大多数它的生活,Haskell的存在理由是帮助探索型系统; 多参数类型类是成功阐明有用的类型系统扩展的一个例子。(从另一方面来说,功能依赖看起来似乎是死路一条。)
geekosaur 2011年

4
@Matthieu:WRT“事实上,也许是存在的类型最强的语言之一。”,我将看您的Haskell,并提高您的AgdaCoq。(我会承认这可能是最强类型的实用语言。)
geekosaur 2011年

1
@Matthieu:校对助手是Curry-Howard函件的直接应用,因此它们是编程语言的核心(尽管标准库相当有限)。它们处于依赖类型研究的最前沿,因为您需要依赖类型以充分利用“类型就是命题”的对应关系。
geekosaur 2011年

37

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

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

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


与我完全一样,每当我要重构某些东西时(我大多使用golang / typescript / java),是的,这两个步骤是任何人都需要的。更改一部分,然后修复所有编译错误:)完美答案。
Nishchal Gautam,

29

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

对于我来说,最重要的是,尽管我失去了一些灵活性,但我获得了一些时间,否则这些时间将花费在查找类型问题上。


13

关于辩论有很多强烈的意见,但显然这实际上不是意见问题,而是事实问题。因此,我们应该研究实证研究。从中得到的证据很明显:

是的,静态类型是值得的权衡-而不仅仅是一点,但实际上基本。实际上,有确凿的证据表明,静态类型化可以将代码中的错误数量减少至少15%(这是一个低估计,实际百分比几乎肯定会更大)。这是一个令人震惊的数字:我想即使是大多数支持静态键入的人也不会想到它产生了如此巨大的变化。

考虑一下:如果有人告诉您,有一种简单的方法可以在一夜之间将项目中的错误减少15%,那应该很容易。1 这几乎是众所周知的银弹。

证据是文件中提出要键入或没有键入:量化在JavaScript中检测的错误由征稿,基督教伯德和伯爵T.巴尔。我鼓励大家阅读它,这是一篇写得很好的论文,展示了杰出的研究成果。

很难简单地总结出作者进行的分析的严格程度,但这是一个(非常粗糙的)概述:

TypeScriptFlow是基于JavaScript的两种编程语言,在保持其他兼容性的同时,还添加了类型提示和静态类型检查。这允许按类型扩充现有代码,然后进行类型检查。

研究人员从GitHub收集了用JavaScript编写的开放源代码项目,查看了已解决的错误报告,并尝试将每个报告的错误减少为一段代码,这些代码将由TypeScript或Flow的静态类型检查器捕获。这使他们能够估计可以通过使用静态类型修复的错误百分比的下限。

研究人员采取了严格的预防措施,以确保他们的分析不会将与类型无关的错误视为与类型相关。2

与以前的研究相比,这项新研究具有特殊的优势:

  • 静态类型动态类型具有直接的比较,几乎没有混杂因素,因为JavaScript和TypeScript / Flow之间的唯一区别是类型。
  • 他们通过检查TypeScript和Flow(即不同的类型系统),并由不同的人员重现(手动)类型注释来修复错误,从而跨多个维度执行复制。他们在来自不同项目的大量代码库中执行此操作。
  • 本文测量了静态类型对可修复错误的直接影响(而不是一些模糊的质量)。
  • 作者定义了一个严格的模型,用于预先衡量什么以及如何进行度量。此外,它们的描述非常清楚,并且易于分析缺陷(当研究论文向攻击开放时,总是很好的:如果没有攻击设法削弱其论点,则结果会更强)。3
  • 他们执行适当的功效分析,以使他们的样本量足够,并且随后的统计分析是不透气的。
  • 他们过于保守,以排除混淆的解释,仅测量单个活动部分。此外,他们通过包含类型将分析范围限制为可立即修复的错误,并排除可能需要进行更高级重构以容纳类型的所有错误。因此,实际上,效果似乎要大得多,但肯定不会比他们报告的小。
  • 最后,他们并没有发现什么微小的影响,而是一个了不起的区别。尽管他们的程序过于保守,但即使在95%置信区间的低端,他们仍然发现至少有10%的错误会通过最少的附加类型检查而消失。

除非该文件中存在尚未有人发现的根本缺陷,否则该文件将最终显示出静态键入的巨大好处,而几乎没有任何成本。4


从历史上看,关于编程中的类型学科的研究起步艰难,因为长期以来,证据不清楚。这样做的原因是,进行系统的实验以检查静态动态类型的影响并不容易:系统的实验必须隔离我们正在研究的影响。不幸的是,由于打字规范与编程语言相关,因此我们无法隔离打字规范的效果。

实际上一些编程语言允许在不同的方言中进行静态和动态键入(例如,带有Option Strict On或的VB Off或静态键入的Lisp)。但是,它们并不适合直接比较,最重要的是,因为不存在允许直接比较的现有足够大的代码库。充其量,我们可以在“实验室设置”中对它们进行比较,在这种情况下,测试对象可以以静态或动态类型的语言变体随机地解决任务。

不幸的是,这些人为编程任务无法很好地模拟实际使用情况。特别是,它们中的许多范围较小,可以解决定义明确的问题,该问题可以总结为半页文本。

幸运的是,这是过去的事情,因为TypeScript,Flow和JavaScript确实是相同的语言(除了静态类型),而且还有大量的实际代码和错误数据集可供选择。


1受到原始论文引用的启发。

2我对此并不完全满意:静态类型语言的主要优势之一是表面上与类型无关的问题可以用可以进行静态类型检查的方式来表述。这将许多逻辑错误转换为类型错误,从而大大提高了静态类型可以捕获的错误的比率。实际上,该论文对与类型无关的错误进行了粗略分类,我认为,其中很大一部分实际上可能是由静态类型捕获的。

3我邀请任何人,尤其是动态类型的支持者,尝试找出分析中未解决的缺陷。我认为并没有很多(如果有的话),并且我相信没有潜在的缺陷会实质性地改变结果。

4我怀疑在实际的大型项目中静态键入的实际成本是不存在的,因为它随后成为体系结构的自然组成部分,甚至可能简化规划。修复静态类型错误需要花费时间,但比以后发现的错误要少得多。对此已经进行了广泛的经验研究,并且已经知道了几十年(请参见例如Code Complete)。


3
我知道这是这个问题的较晚答案,但是我相信新证据(我在这里解释)改变了完整的静态对动态辩论。
康拉德·鲁道夫

2
这当然很有趣,但是我想知道它与javascript的特定类型系统有多少关系。Python的(特别是python3)类型系统要严格得多,隐式转换要少得多。
彼得·格林

@PeterGreen是的,毫无疑问,这是真的。也许我们很幸运,Python的类型提示将导致日后的类似分析(尽管我对此表示怀疑,因为PEP484和PEP526的明确目的不是实现静态类型)。
康拉德·鲁道夫

1
仅仅阅读摘要,我已经可以确定该方法从根本上来说是有缺陷的。您不能使用使用一种学科编写的代码库,而只能添加类型以证明完全不同学科中的参数合理。编写为静态规则的代码在本质上看起来与动态规则完全不同,您不应该用Python编写Java,就像您不应该用Java编写Python一样。尽管表面上相似,但即使打字稿和javascript也是根本不同的语言。
Lie Ryan

2
@LieRyan是否有使分析过于保守的内容,如我的描述和其他地方所述。它绝不会使分析无效。老实说,您的1%估算是可笑的。这完全没有了,你的直觉让你失望了。同样,您对静态类型问题的刻画是动态类型从业人员的典型代表,他们几乎没有现代静态类型(即不只是Java)的实际经验。
康拉德·鲁道夫

12

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

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

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

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

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


我已经有一段时间的印象是,编程语言应该只隐藏您不需要考虑的代码功能。这样一来,就可以将机器代码一直提升到Java之类的更高层次,因为您基本上不需要处理较低级别的实现。对象类型不是这种情况。在我看来,动态键入只会使编程变得更加困难,因为它会引入一整类错误,您必须自己去解决。
MCllorf

7

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

重申我的回答的核心:

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

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

就个人而言,我在haXe中进行大部分开发,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中-尽管可能不会很快)。


在python中,doctest只是从repl / shell复制并粘贴,作为文档和以后检查的来源。 docs.python.org/3/library/doctest.html
aoeu256

5

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

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

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

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

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


5

这取决于。

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

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

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


3
Paul Hudak关于美国海军研究的论文暗示了您快速原型化的场景是错误的,该论文需要开发使用不同语言的类似AEGIS的模拟,其中之一就是Haskell。它几乎满足您的所有条件:快速成型,定义不明确的要求以及失败的成本几乎为零(这是一个非常非正式的实验)。Haskell在evey类别中脱颖而出:开发时间,超出要求,要求的LOC更少,并且是所有参赛者中唯一可行的示例
安德烈斯·F

2
论文:Haskell与...,软件原型生产力的实验-Paul Hudak和Mark P. Jones。它描述了ARPA和美国海军订购的实验结果。
Andres F.

赢家不是Relational Lisp吗?伙计,我希望有一些视频能够显示人们使用Lisp等所有怪异的强大扩展来用Lisp编码事物(Shen(一种逻辑关系框架,它允许您为代码提供从属类型,并为非类型代码提供混合匹配类型的代码) ),具有谓词分派的超级CLOS框架等
aoeu256

4

有很多用Lisp编写的非常复杂的系统,而且我还没有听到任何Lisper抱怨他们需要静态类型。当我使用它时,我不记得有什么问题让我感到失望,因为它会使静态类型系统(您可以在Common Lisp中静态指定类型)陷入困境。

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


4

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

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

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


3

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


4
Java和C#等强类型语言通过使用Reflection自动处理反序列化。
Matthieu M.

3

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

  1. 使旧代码保持静态,不灵活的语言。使用Python制作新东西。
  2. 使用Python在成熟的平台上为新事物创建原型。用更成熟的语言重新编码要保留的组件。
  3. 对经常更改的部分使用动态语言。
  4. 可能使用动态语言来处理诸如修改运行代码之类的想法。
  5. 除了使用强类型语言的关键部分以外,还应使用动态语言进行所有操作。

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

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


2

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


这是一个主观的质量检查,因此我对此表示满意。
Morgan Herlocker 2011年

1
有人介意解释投票否决吗?
pdr

无法为您提供解释,但我给了您+1,我认为这是一个有用的贡献。动态类型的主要担心之一是,由于编译器会以静态类型的语言强制执行这些假设,因此您将在某处进行更改并在其他地方进行更改。大量的单元测试范围将在这里保护您。
Carson63000 2011年

5
尽管您没有提出冒犯的意图,但我并没有拒绝投票,但您的帖子有点像TDD的狂热分子,这可能就是为什么拒绝投票的原因。
Karl Bielefeldt

@Karl,没有冒犯,这是一个真正的问题。我承认,我可以毫无诚意地支持TDD
博士

2

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

我的最后工作主要是python开发。我曾在一家大型国际网络托管公司工作,我们在美国,加拿大和韩国设有开发团队。用于前端客户应用程序的自定义python Web框架,允许用户管理其域名和Web托管帐户。后端:也是所有python。Python Web服务可以与各个服务器进行通信,以进行诸如设置新的Web托管站点,创建新的博客,在我们的名称服务系统中创建dns条目之类的工作;在我当前的工作中,客户端应用程序全部使用Java;我们的主要产品是Java和Flash的混合物。针对我们较旧的应用程序的自定义Java Web框架,对于我们较新的内部工具的自检。

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


2

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

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

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

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

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

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

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


1

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

我已经很长时间了。从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个开发人员正在做不同的事情,他们现在都已停止并等待让有问题的开发人员纠正错误。谈高效吧?类型系统/静态语言以这种方式相互依赖,并使您的代码相互依赖。但是,脚本文件从不相互依赖。如果其中一个脚本有问题,它不会停止生产,那么您看到的所有问题都将留给运行时。而且运行时永远不会停止。永不中断。它可能会产生错误的输出,但不会


1
很多“我”,没有很多论点。顺便说一下,错误是否“破坏”了构建与静态还是动态无关。如果您进行了单元测试,但失败了,则“您的构建已被破坏”,并希望在更正之前不要部署到生产中
nafg 2015年

是什么让您认为我暗指任何此类事情?
nafg

您的javascript生产力没有飞速增长,因为javascript缺少类型。由于C ++和C#是笨拙的语言,因此您的生产力飞速增长。Javascript +类型实际上将使您的生产力进一步提高。没有人说过JavaScript对于大型项目是不可能的。大型项目上的Javascript当然是可行的。但是,这不是理想的。单元测试代替类型检查,单元测试的类型覆盖率也有限,而类型检查的覆盖率则为100%。
Brian Yeh

1
@BrianYeh c ++和c#是繁重的语言,因为它们以类型为中心。我刚刚开始在工作中使用reactjs,由于对类型和组件的频繁使用,我的生产力再次下降。如果您喜欢类型和单元测试,则对您有好处。并非我们所有人都共享这种编程风格。

1
@foreyez reactjs没有类型。您可能是指流程。单元测试代替了类型检查,因此,如果没有类型检查,则需要更多的单元测试。单元测试和类型是相反的力量。您的生产力下降是一种幻想。使用类型安全语言捕获的任何类型错误都是动态类型语言中未捕获的错误。它只会显得更快。类型安全的语言会迫使您提前处理这些错误。
Brian Yeh

0

是。

我曾在PHP应用程序中工作过,其中类型不像Java或C#那样“强”。通常我会完成“模拟类型”,因为为了避免不良的自动转换或验证数据。

动态类型语言适用于OS脚本和快速的小型应用程序,而不是复杂的应用程序。

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


0

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

一种情况是根本不对代码分支进行测试,但是坦率地说,无论是否使用动态类型,从未测试的代码都可能会出错。

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

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

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

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

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

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


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

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.