我想知道的是,人们究竟觉得动态语言有什么吸引力?使用动态语言有哪些主要优势,这些优势难以在编译型语言中实现或者实现起来很困难?我觉得我们很早之前就已经认定像未编译的ASP页面抛出运行时异常这样的事情是个坏主意。为什么这种代码类型又重新兴起了?而且,至少在我看来,Ruby on Rails看起来并不像你在10年前不能用ASP实现的东西。
我想知道的是,人们究竟觉得动态语言有什么吸引力?使用动态语言有哪些主要优势,这些优势难以在编译型语言中实现或者实现起来很困难?我觉得我们很早之前就已经认定像未编译的ASP页面抛出运行时异常这样的事情是个坏主意。为什么这种代码类型又重新兴起了?而且,至少在我看来,Ruby on Rails看起来并不像你在10年前不能用ASP实现的东西。
我认为原因是人们习惯于静态类型语言,这些语言具有非常有限和表达能力不足的类型系统。这些语言包括Java、C++、Pascal等。与其朝着更具表现力的类型系统和更好的类型推断方向发展(例如Haskell,甚至是SQL在某种程度上),有些人喜欢将所有“类型”信息都保留在头脑中(以及测试中),并完全放弃静态类型检查。
最终这样做给你带来的好处是不明确的。关于类型检查有许多误解,我经常遇到的两个误解如下:
谬论:动态语言不那么啰嗦。 误解在于类型信息等同于类型注释。这是完全不正确的。我们都知道类型注释很烦人。机器应该能够找出那些东西。实际上,在现代编译器中它也确实能找出来。下面是一个用两行Haskell编写的静态类型的快速排序(摘自haskell.org):
qsort [] = []
qsort (x:xs) = qsort (filter (< x) xs) ++ [x] ++ qsort (filter (>= x) xs)
这里是一个使用LISP实现的动态类型快速排序(来自swisspig.net):
(defun quicksort (lis) (if (null lis) nil
(let* ((x (car lis)) (r (cdr lis)) (fn (lambda (a) (< a x))))
(append (quicksort (remove-if-not fn r)) (list x)
(quicksort (remove-if fn r))))))
这个Haskell的例子推翻了“静态类型语言通常很啰嗦”的假设。而LISP例子则反驳了“啰嗦的语言是静态类型的”这一假设。类型和冗长之间没有任何因果关系。你可以放心地不用考虑这点。
谬论:静态类型语言只能编译,不能解释。同样不正确。许多静态类型语言都有解释器。比如Scala解释器、Haskell的GHCi和Hugs解释器,当然SQL也一直以来既是静态类型又是解释型。
也许动态派想要的只是不必认真思考就能写出软件的自由。这样写出来的软件可能不正确也不健壮,但也许这并不重要。
就我个人而言,我认为那些为了购买一点暂时的自由而放弃类型安全的人,既不配得到自由,也不配得到类型安全。
不要忘记,在单元测试中编写的代码覆盖率需要达到10倍,以替代编译器提供的功能:D
我已经使用过动态语言并尝试过这种做法,但是我没有看到任何优势。
在阅读他人回复时,似乎有更多或更少的三个关于动态语言的论点:
1)代码不太冗长。我不认为这是有效的。一些动态语言比一些静态语言不那么冗长。但F#是静态类型的,但其中的静态类型并没有增加多少代码,如果有的话。它是隐式类型的,但那是另一回事。
2)“我最喜欢的动态语言X有我最喜欢的函数特性Y,因此动态更好”。不要混淆功能和动态(我不明白为什么必须这样说)。
3)在动态语言中,您可以立即看到结果。新闻:您也可以在Visual Studio中使用C#(自2005年以来)做到这一点。只需设置断点,在调试器中运行程序并在调试期间修改程序即可。我一直这样做,而且效果非常好。
就我个人而言,我非常支持静态类型,主要原因是可维护性。我有一个包含几万行JavaScript的系统,任何我想要进行的重构都需要花费大约半天的时间,因为(不存在的)编译器不会告诉我那个变量重命名搞砸了什么。而那是我自己编写的代码,我认为结构良好。我不想被委任负责一个等价的由其他人编写的动态系统的任务。
我想我会因此遭受大规模的贬值,但我愿意冒险。
除非与其他版本的VB进行比较,否则VBScript很糟糕。 PHP还不错,只要记住它是一个过度臃肿的模板语言。 现代JavaScript非常棒。真的。非常有趣。只要远离任何标记为“DHTML”的脚本即可。
我从未使用过不允许运行时错误的语言。在我看来,这在很大程度上是一个诱导人误入歧途的问题:编译器无法捕获所有的拼写错误,也无法验证意图。当需要明确类型时,显式类型很棒,但大多数时候不需要。在此处搜索有关通用类型或使用无符号类型作为索引变量是否是一个好选择的问题 - 大多数情况下,这些东西只会妨碍工作,并为人们提供了一些可以调整的旋钮以消磨时间。
但是,我还没有真正回答你的问题。为什么动态语言具有吸引力?因为经过一段时间后,编写代码变得乏味,您只想实现算法。您已经坐下来用笔计算出所有可能出现的问题场景并证明了它们是可解决的,现在唯一剩下的就是编写20行实现代码...和200行的样板代码使其编译。然后您意识到,您使用的类型系统并不反映您实际正在做的事情,而是某个人超级抽象的想法,即您可能正在做的事情,并且您早已放弃了编程,进入了一种沉迷于小物件调整的生活,这甚至会让虚构侦探阿德里安·蒙克感到羞耻。
那就是当你开始认真看待动态语言的时候。
我是一名全职的.Net程序员,完全陷入了静态类型的C#编程之中。然而,我喜欢现代的JavaScript。
总体来说,我认为动态语言比静态类型语言更能简洁地表达你的意图,因为你花费更少的时间和空间定义你尝试表达的构建块,这在许多情况下是不言自明的。
我认为动态语言有多个类别。我没有回到用VBScript编写经典ASP页面的愿望。为了有用,我认为动态语言需要支持某种集合、列表或关联结构,在其核心表达对象(或可以传递为对象)并允许您构建更复杂的结构。(也许我们都只应该在LISP中编码……这是一个玩笑…)
在.Net圈子里,动态语言因为与VBScript和/或JavaScript相关联而声名狼藉。VBScript因为Kibbee所述的原因而令许多人想起噩梦-还记得使用CLng强制类型以确保获取32位整数的足够位吗?此外,我认为JavaScript仍被视为为所有浏览器编写不同的下拉菜单的浏览器语言。在那种情况下,问题不在语言本身,而在于各种浏览器对象模型。有趣的是,随着C#不断成熟,它看起来越来越动态了。我喜欢Lambda表达式、匿名对象和类型推断。它感觉每天都更像JavaScript。
这是从haskell.org上抽取的两行Haskell实现的静态类型快速排序:
qsort [] = []
qsort (x:xs) = qsort (filter (< x) xs) ++ [x] ++ qsort (filter (>= x) xs)
这里是一个用LISP编写的动态类型快速排序示例(来自swisspig.net):
(defun quicksort (lis) (if (null lis) nil
(let* ((x (car lis)) (r (cdr lis)) (fn (lambda (a) (< a x))))
(append (quicksort (remove-if-not fn r)) (list x)
(quicksort (remove-if fn r))))))
我认为你在选择语言时有所偏见。Lisp以括号数量繁多而著称。更接近Haskell的语言是Python。if len(L) <= 1: return L
return qsort([lt for lt in L[1:] if lt < L[0]]) + [L[0]] + qsort([ge for ge in L[1:] if ge >= L[0]])
这里的Python代码
对于我来说,动态语言的优点在于代码变得更加易读,因为有更少的代码和类似Ruby块和Python列表推导式这样的函数技术。
但是我有点想念编译时检查(拼写错误确实会发生)和IDE自动完成。总的来说,代码量更少和可读性更高对我来说很划算。
另一个优点是语言通常是解释性/非编译性的。更改一些代码并立即看到结果。这真的是开发过程中的时间节省者。
最后但并非最不重要的是,我喜欢你可以启动一个控制台,尝试一些你不确定的东西,比如一个以前从未使用过的类或方法,看它的行为如何。控制台有许多用途,我会让你自己去发现。
你提到动态语言的缺点是完全合理的。不过请考虑以下几点:
刚开始时离开安全的静态类型世界可能会让人有些害怕,但对我来说,优点远远大于缺点,我再也没有回头看过去。
这三个特点并不是动态语言专有的,但它们显然不存在于今天流行的静态语言Java和C#中。您可能会争辩说C#有第二个特点(委托),但我认为它根本没有被广泛使用,例如在列表操作中。
至于更高级的静态语言... Haskell是一种非常好的语言,它具有1和2,虽然没有3,但它的类型系统非常灵活,您可能不会发现缺少元编程限制了它。我认为您可以使用语言扩展在OCaml中在编译时进行元编程。Scala是一个非常新的补充,非常有前途。对于.NET阵营,F#也是如此。但是,这些语言的用户是少数,因此他们并没有真正促进编程语言格局的变化。事实上,我非常相信Ruby的受欢迎程度以积极的方式影响了像Haskell、OCaml、Scala和F#等其他动态语言的受欢迎程度。
个人认为,你所使用的大多数“动态”语言只是一般语言的差劣例子。
使用Python比使用C或Java更高效,这不仅仅是因为你必须进行编辑-编译-链接-运行的过程。我在Objective-C中也变得更加高效,但这可能更多地归功于框架。
不用说,我在任何这些语言中都比PHP更高产。该死的,我宁愿用Scheme或Prolog编码,也不要用PHP。(但最近我做的其实是更多的Prolog,所以这话要谨慎!)