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

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

这不是语言比较,因此请不要解决诸如编译与解释之类的问题。类型安全是否值得在开发速度和灵活性方面受到打击?为什么要向想要一个例子的人举例说明动态键入的速度更快:


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


评论

这个问题与“哪些参数支持弱类型?”相反。

@Prof Plum:我是否需要证明开发速度和灵活性受到打击?由于我们在谈论类型安全的特定方面,因此使用Java或C#尚无定论,因此他们提供它的方式并非唯一...

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

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

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

#1 楼

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

在动态类型语言中:


您仍然必须知道是否要使用数组,整数,字符串,哈希表,函数引用,字典,对象或其他内容。
如果是对象,则必须知道它属于哪个类。
将这些类型之一分配给预期为另一种类型的变量或函数参数几乎总是错误。
例如,如果要填充TCP数据包,则仍必须考虑较低级别的位数,有符号或无符号。
您可能会遇到问题,在您真正想要一个空字符串的地方得到零。换句话说,您仍在调试类型不匹配的错误。唯一真正的区别是编译器没有捕获错误。
我认为您甚至没有节省很多type-,因为您倾向于在注释中记录函数参数的类型而不是将其记录在您的代码中。这就是为什么doxygen样式的注释块在整个动态类型代码中在实践中更为流行的原因,在静态类型语言中,您通常只在库中看到它们。

这并不是说以动态类型语言进行编程感觉并不令人愉快,因为编译器并不总是在您的支持下,而且经验丰富的程序员也不容易发现并纠正静态类型仍然会捕获的错误类型,但这与所谓的问题完全不同提高效率或减少错误率,对于动态类型,即使使用静态类型,充其量也是最好的选择。

评论


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

–杰伊·杰伊(Jay Jay Jay)
2014年3月4日,3:32

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

– Severyn Kozak
2015年6月29日在21:45



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

–weberc2
16年2月8日在20:54

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

–罗德里戈·鲁伊斯(Rodrigo Ruiz)
16年7月5日在5:27

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

–aoeu256
19年7月1日在21:53

#2 楼

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

评论


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

–乔治
2012年2月24日在17:01

一个简单,更好的答案-softwareengineering.stackexchange.com/a/215532/260655

– MasterJoe
20年4月18日在19:18

#3 楼

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

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

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

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

此外,Haskell使用类型推断,因此您不必声明变量的类型。它们是在编译过程中静态计算的,就像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]


在浏览器中尝试一下

评论


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

– T.R.
2011-3-18在21:08

我不知道Haskell,但为+1表示“实际上是在抱怨别的东西(冗长,从一种类型转换为另一种类型的痛苦)”

–妮可
2011-3-18在22:08

@Aidan:Haskell是一种不断发展的语言。 Haskell 98是对Haskell 1.4的改进。 Haskell 2010是对此的改进。同时,值得注意的是,Haskell在其整个生命的大部分时间内都是用来帮助探索类型系统的。多参数类型类是成功阐明有用的类型系统扩展的一个例子。 (从另一方面来说,功能依赖性似乎是一个死胡同。)

– geekosaur
2011年3月19日下午4:43

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

– geekosaur
2011-3-19在4:51



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

– geekosaur
2011年3月19日17:19



#4 楼

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

1)您通常可以从其类型签名中完全推断出函数的功能(这在Haskell这样的函数语言中尤其如此)。 />
2)当您进行重大重构时,编译器会自动告知您为使一切正常运行而必须做的一切。当我用C ++重构某些东西时,我的过程通常很简单:a)更改我知道要更改的部分,然后b)修复每个编译错误。

评论


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

– Nishchal Gautam
18年9月12日在0:29

#5 楼

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

对我来说,最重要的是,尽管我失去了一些灵活性,我花了一些时间来寻找类型问题。

#6 楼

围绕辩论有很多强烈的意见,但显然这实际上不是意见问题,而是事实问题。因此,我们应该研究实证研究。显而易见,证据是这样的:

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

考虑一下:如果有人告诉你,有一种简单的方法可以在一夜之间将项目中的错误减少15%,这应该是不费吹灰之力。1这几乎是众所周知的灵丹妙药。

证据显示在论文中打字还是不打字:量化可检测Zheng Gao,Christian Bird和Earl T.Barr编写的JavaScript错误。我鼓励大家阅读,这是一篇写得很好的论文,提供了示例性研究。

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

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

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

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

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


可以直接比较静态类型和动态类型,几乎没有(如果有)混杂因素,因为JavaScript和TypeScript / Flow之间的唯一区别是类型。
它们执行复制。通过检查TypeScript和Flow(即不同的类型系统),并由不同的人员重现(手动)类型注释来修复错误,从而跨多个维度。并且他们在来自不同项目的大量代码库中执行此操作。
本文测量了静态类型对可修复错误的直接影响(而不是模糊的质量)。
作者定义了一个严格的模型先要衡量什么以及如何衡量。此外,它们的描述非常清晰,并且易于分析缺陷(当研究论文向攻击开放时总是很好的:如果没有攻击设法削弱其论点,它就会变得更强大)。3

他们进行适当的功效分析,以使它们的样本量足够大,并且随后的统计分析是不透气的。
他们过于保守以排除混淆的解释,仅测量单个运动部分。此外,他们通过包含类型将分析范围限制为可立即修复的错误,并排除可能需要进行更高级重构以容纳类型的所有错误。因此,实际上,效果似乎要大得多,但肯定不比他们报道的要小。
最后,他们发现的效果不是很小,而是巨大的差异。尽管他们的程序过于保守,但即使在95%置信区间的低端,他们仍然发现至少有10%的错误会通过最少的附加类型检查而消失。

除非论文中没有人发现的根本缺陷,否则论文将最终显示出静态打字的巨大好处,而且几乎没有成本。4


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

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

不幸的是,这些人工编程作业无法模拟现实世界用法很好。特别是它们中的许多方法范围很小,可以解决一个定义明确的问题,该问题可以总结为半页文本。

幸运的是,这已经过去了,因为TypeScript,Flow和JavaScript确实是除了静态类型外,它们是相同的语言,并且因为有大量的真实世界的代码和错误数据集可供选择。


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

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

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

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

评论


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

–康拉德·鲁道夫(Konrad Rudolph)
18年5月22日在18:49



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

– Peter Green
18年5月22日在21:05

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

–康拉德·鲁道夫(Konrad Rudolph)
18年5月23日在9:01



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

– Lie Ryan
19年8月3日在4:49



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

–康拉德·鲁道夫(Konrad Rudolph)
19年8月3日,12:34



#7 楼


类型安全值得在开发和灵活性上取得成功吗?


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

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

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

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

评论


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

–男人
19年5月14日在2:37



#8 楼

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

重申我的回答的核心:


随着系统的不断发展,静态地
类型化语言可确保组件级的鲁棒性,从而确保系统级的灵活性。


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

我个人大部分的工作都是在haXe中进行的,haXe具有静态类型系统。它不仅比Java更具表现力,而且由于类型推断而需要的工作量也少得多,而且它是可选的。

绕过它。

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

我认为,静态类型系统令人讨厌的说法仅仅是基于缺乏良好静态类型系统的知识。有很多语言可以做到这一点,haXe是其中的一种,甚至可以说在这方面不是最好的。

示例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
19年7月20日在14:23



#9 楼

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

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

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

在Hindley-Milner的静态类型传统中,您可以构建的东西不仅可以保证类型声明支持接口X,而且还可以为您提供保证,一旦拥有这些东西,我就说

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

#10 楼

这要视情况而定。

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

这种减少潜在失败几率是否值得付出成本的决定。

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

评论


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

– Andres F.
2015年8月6日19:35



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

– Andres F.
15年8月6日在19:38

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

–aoeu256
19年9月28日在0:15

#11 楼

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


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

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

#12 楼

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

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

#13 楼

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

评论


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

– Matthieu M.
2011年3月18日在18:31

#14 楼

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


以静态,僵化的语言保留旧代码。使用Python编写新内容。
使用Python在成熟平台上为新内容制作原型。使用更成熟的语言重新编码要保留的组件。
对经常更改的部分使用动态语言。
可能使用动态语言来玩弄修改运行代码之类的想法。
除了使用强类型语言的关键部分以外,都应使用动态语言进行所有操作。

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

(注:已经有人回答了,但我也想再次强调一下动态类型! =否/弱类型。许多动态类型系统在内部使用强类型。我考虑使类型动态的原因是变量类型在运行时确定,不需要类型注释和/或可能会改变在运行时。

#15 楼

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

评论


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

–摩根·赫洛克(Morgan Herlocker)
2011年3月18日在18:21

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

– pdr
2011-3-18在18:26

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

– Carson63000
2011年3月18日在20:54

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

–卡尔·比勒费尔德(Karl Bielefeldt)
2011-3-18在22:19

@Karl,没有冒犯,这是一个真正的问题。我承认,我可以坚定地支持TDD

– pdr
2011-3-18在22:40

#16 楼

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

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

两者都工作过,每次见到这个问题我都会说。如果您使用的是动态类型的语言并实际测试您的代码,则可以。如果系统设计良好,并且您遵循标准,那么您会没事的。由于缺少编译器检查类型,因此不会出现很多错误。就像我今天的Java工作一样,大多数错误都是逻辑错误。

#17 楼


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

软件开发的原因是:


您要完成的工作固有的复杂性
人类固有的易犯性,尤其是考虑到在尝试做某事时会犯更多错误更复杂

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

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

#18 楼

是。

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

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

摘要:如果我必须在“弱类型”或“动态类型”编程语言或“强类型”编程语言之间进行选择复杂的业务应用程序,我选择“强类型”编程语言。

#19 楼

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

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

评论


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

– nafg
2015年5月29日晚上10:45

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

– nafg
15年7月7日在21:01

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

–叶rian
18年1月21日在10:37

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

–user19718
18年1月22日在18:42

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

–叶rian
18年1月22日在20:11

#20 楼

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

一种情况是根本没有测试代码分支,但是坦率地说,从未测试过的代码可能会

另一个麻烦的问题是可替代性不完善。

如果类型是完全错误的,除非没有特定的代码路径可能很快就会被发现。

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

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

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

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


我在这里得到的是我认为无法比较收益和成本以静态方式进行静态和动态类型化,因为我认为收益和成本都取决于语言使用的静态或动态类型的特定变化。