程序员不再那么谦逊了——也许是因为没人再用 Perl 编程

图0:程序员不再那么谦逊了——也许是因为没人再用 Perl 编程

Perl 是一种杂乱无章、令人抓狂的编程语言,是“互联网的万能胶带”。但至少你能看出它是人类创造的。

Perl 曾经无处不在。或者至少感觉是这样。千禧年之际,似乎每个网站都是基于这种脚本语言构建的。它处理海量文本——实现这一功能的强大且便捷的机制是语言本身的一部分——甚至被用于生物信息学,处理和分析遗传数据。根据一份列表,使用 Perl 的公司范围广泛:亚马逊、谷歌、雅虎、德意志银行、Akamai、花旗银行、康卡斯特、摩根士丹利、Mozilla。Craigslist 的很多部分都是用 Perl 编写的。

即便在使用高峰期,Perl 的流行程度也始终令人有些意外。Perl 毫无疑问是一种杂乱无章的语言。它常被戏称为“互联网的胶带”,程序员们开玩笑说它是一种“只写不读”的语言: 你用它编写代码,但很少能成功阅读它(至少是成功地阅读)。

元素周期表

Perl 具有一种混合拼凑的特性,这一切都服务于它的座右铭:“实现同一目标的方法不止一种。”正如英语中有同义词一样,Perl 也有多种方法来编写相同的内容。虽然这种特性在一定程度上是编程语言的常见特征,但 Perl 似乎想要用它来敲打你的头脑。例如,编写条件语句有多种方式,从使用传统的“if”到“unless”;到在单行中倒置编写if语句;甚至还有一个涉及问号和冒号的三部分运算符。我清楚地记得,在21世纪初,有一天我用Perl编写代码,第二天却不明白自己写了什么。

但这种杂乱无章和巴洛克式的结构实际上是故意为之,是Perl背后更广泛哲学的一部分。该语言的创建者拉里·沃尔(Larry Wall)接受过语言学训练,他的初衷是与妻子一起成为一名传教士从事稀有语言研究。沃尔最终选择了不同的道路,全身心投入编程。但他对语言运作机制的深刻思考从未离开过他。

沃尔的观点似乎是,对语言纯洁性的执着追求被高估了。英语中包含法语、希腊语、德语甚至阿卡德语的词汇,这反映了其曲折的历史和多元的起源。我们拆分不定式,悬置修饰语。我们有双关语,无论是故意还是无意的。那么,在编写if语句时,一点点怪异又何妨?沃尔认为,进化是语言发展过程的一部分。这里有一个有机过程在进行,最终产物不必井然有序。因此,对语言构造采取一种宽容且不带偏见的态度至关重要,无论是设计用于编写脚本还是十四行诗的语言。

Perl 有其“多种方式”来完成事情,而英语则拥有多种风格和灵活的特性,这种特性可以涵盖从烹饪食谱到俳句、从购物清单到福克纳的作品。这就是真正开放性的标志。正如Wall曾说过: “我坚信,一种语言……应当是一种无道德倾向的艺术媒介。”如果 Perl 有任何宏大的愿景或教条,那或许只是因为,或许根本不应该存在编程教条。

需要明确的是,我从未成为 Perl 的深度用户。它的语法和混乱性让我感到其力量被掩盖,当我接触到Python井然有序的结构时,我立刻转向了这门语言,并且从未真正回头。这或许正是该语言失去光环的原因。即便在1998年其鼎盛时期,已有观点认为Perl的臃肿可能促使人们转向更“干净”的语言。无论原因如何,Perl已不再像过去那般流行。

然而,我仍会不时回到这门奇特的语言,我认为这源于其核心的谦逊精神。我们需要谦逊,因为我们意识到这个世界比我们所能理解的更加复杂,尤其是在涉及我们自己创造的大型技术系统(人工智能,咳咳)时。在一个充满例外情况、边界案例和复杂问题的世界里,单一的综合理论或模型是行不通的。我们需要缓慢而笨拙的方法,而 Perl 的多元主义演变可以为我们指明方向。

Perl 甚至能让我们更了解自己。如果让我选择一种与 Perl 最为不同的编程语言,那可能是 Lisp。Lisp 诞生于 20 世纪 60 年代,其设计优雅,几乎具有数学般的结构。正如其定义所描述的——这只是为了让你感受一下它的深奥性。Perl 当然不是这样。它有机且有时令人抓狂。换句话说,尽管它杂乱无章,但它是一种属于人民的语言。

这就是编程语言的本质:它们实际上是为人类设计的;它们不能仅仅被机器解析。在经典教材《计算机程序的结构与解释》中,作者们明确指出: “因此,程序必须为人类阅读而编写,仅次要地为机器执行。”是的,关于 Perl 的笑话是它“只写不读”——但你总能看出它是人类编写的。

我承认,Perl 的复兴是不太可能的。但或许 Perl 的启示是永恒的。它提醒我们在编程语言及其设计上要少些拘谨,多些人性。只有这样,我们或许才能弥合人与机器之间的鸿沟。

本文文字及图片出自 Programmers Aren’t So Humble Anymore—Maybe Because Nobody Codes in Perl

共有 205 条评论

  1. 我记得通读了O'Reilly的《Perl入门》[0]一书,并觉得书中的内容都很有道理——($)标量、(@)数组和%字典(因为我们用一对“o”表示键值对)等等。作为一个只写Bash脚本的人(周围的人也都是写Bash),这感觉就像一夜之间变成了超级英雄。我把所有的Bash脚本都重写成了Perl,获得了高级语言特性和极快的运行速度。我喜欢拿别人的Bash脚本(需要花一个小时完成的),用Perl重写成只需几分钟就能完成的版本(虽然从客观上来说性能很差,但当时我还是个新手程序员,别人也不知道更好)。我成了风头人物。那种感觉太棒了。

    后来我获得另一个职位,仅仅是因为找不到 Perl 程序员,而我在这方面还算不错。但这是一个由一群想写聪明代码的人开发的实际应用程序,就像把导弹库的钥匙交给一群纵火犯一样。数千行代码。到最后,我被告知我们需要转用Java,我几乎抑制不住自己的 relief。

    对于一次性脚本,仍然没有比Perl更流畅的语言。这是我编程过的最有趣的语言,毫无疑问。

    [0] 更正:学习Perl,骆驼书(感谢@ninkendo)

    • 你偷了我的故事! 🙂

      我在计算机科学项目中是个平庸的开发者和学生,甚至曾考虑过退学。但我真的很喜欢系统和构建解决方案,最终成为了一名数据库管理员(DBA)。

      不知为何,我的思维模式与Perl高度契合。我几乎能像写作一样使用它,先用Perl勾勒出“大纲”,随后通过更高效的C代码或第三方工具进行重构和补充。

      这很酷,我开始解决数据集成问题并自动化数据库相关的流程。最终,我和一位同事基本上开发了一个应用程序,使我们的灾难恢复测试的故障转移和故障回退流程变得只需两次点击即可完成。我早已离开那家公司,我知道我们的大部分系统在迁移到AWS之前运行了近20年。

      如今IT行业更加工业化和高效化。这并非坏事,但我曾乐在其中,作为那个向老一辈展示Linux并整合这些系统以实现协同运作的“孩子”。遗憾的是,Perl已成为那个时代的遗物。

      • 当我用Python重写一些损坏/不兼容的C代码时,我也有同样的感觉。这并没有提升性能,但它确实重新点燃了那种黑客心态,用一种清晰易懂的语言编写代码。我向学生展示我的Flask设置,我可以看到他们脑海中灯泡亮起的瞬间。

        较旧的语言可能是我们这个时代代码的遗物,但我很期待看到下一波文档化提示式编程带来的新趋势。

        我终于明白学生们的代码在做什么了!哈哈!

    • 这里可以写很多内容,我完全同意你的观点——在处理文本流方面,几乎没有比Perl更好的选择。

      即使PHP的流行(及其易用性)也可以追溯到它从Perl借用的部分;毕竟,网络本质上就是对文本的操作。

      我经历了与你类似的历程。从C语言起步,转而使用Bash,随后用Perl替代Bash脚本,你说的没错,这确实让人感觉像获得了超能力。

      但我编程生涯中最有趣的语言可能是Ruby,因为它彻底改变了我对语言的认知。在Ruby中,一切都是对象且一切皆可变——这使得动态元脚本的可能性简直令人难以置信。

      我不再倡导这些语言,因为Perl很容易变成“写一次,永远不读”,这种情况比bash还要糟糕——但我忍不住觉得,我们确实失去了一种处理文本的杀手级语言。似乎没有人再写Perl了。

      • > 目前仍没有比 Perl 更适合处理文本流的语言。

        这确实如此,但这掩盖了我认为更深层的真相:用 Perl 思考自然会导向“文本流”的思维方式,这是一种在 Unix 世界中已被 largely 遗忘的通用组合性。

        如今每个项目都有自己庞大的依赖列表、自己的代码结构规范、自己的辅助工具链实用程序列表(如代码检查器和格式化工具)。甚至还有自己的一套Visual Studio Code扩展,你几乎不得不使用它们。

        工具不再只是工具。

        • 完全同意。尽管软件如今总体上更可靠,但它绝非可组合的,而即兴编写解决方案的能力也已丧失。

          人们常常希望系统具备可脚本化特性……它们曾具备过,但人们却毁掉了让这一切成为可能的机制。

      • 我也是 🙂

    • 《骆驼书》。

      那些奥莱利(O'Reilly)的书籍有一种令人愉悦的接地气和人性化的特质。但实际上,大多数IT书籍都有一种随性、有趣且富有创造力的特质。这种品质如今已很少见。

      • 骆驼书是《Perl编程》,主要面向已有编程经验的读者,如果我记得没错的话……还有一本骆驼书《学习Perl》,可能就是GP所指的那本?

        《学习Perl》(骆驼书)是我第一本编程书籍,它教会了我编程的通用知识,而不仅仅是Perl,我至今仍认为这是一本了不起的书。非常易于理解,对初学者很有帮助,我从头到尾读完了它。还有《学习Perl对象引用和模块》,可以说是《学习Perl》的续集。这两本书帮助我获得了第一个Perl程序员的工作,并开启了我的整个职业生涯。

      • 这是我真正喜欢的第一本书。我读过好几次,没有特定的顺序,就像沉浸在享受美味零食一样。

      • ……可惜的是,如今这些书在印刷时已经过时了。

      • 也许

        但我完全看不懂。

        因此我转而成为网络安全领域的经济学家。

    • 听起来很熟悉。对我来说,我当时在写批处理脚本,那本书是《学习Perl在Win32系统上》。其他情况都一样。

    • 啊,大学时我写过一篇比较Perl、Python和Tcl/Tk的论文。

      Tcl无疑是最易于使用的,而Perl则在技能要求和可读性方面都处于另一端。

      正如那句格言所说:“力量,但代价是什么?!”

      • 现代Python比当年Perl 5脚本中的任何内容都复杂得多。类型提示、随处可见的装饰器、像numpy这样的大型框架迫使你的问题符合特定的范式。现代对异步和可迭代性的关注,使得即使是简单的代码也变得“颠倒过来”。这很复杂!

        有趣的是,这种复杂性在思维空间上与 Perl 有很多相似之处。Perl 之所以伟大,是因为你可以变得“聪明”,而在更通用的语言中你真的做不到。

        我发现(我不确定这是否是件好事),我现在的 Python 输出有时感觉非常聪明……

  2. 我曾以编写可读性强、易于维护的 Perl 代码为荣。

    我曾在一家特效公司工作,那里的大部分系统都是用 Perl 编写的,这些代码跨越了大约 15 年。其中一些代码很巧妙,但大多数都是简单易读的脚本。

    保持代码可读性的关键在于良好的代码审查,以及有人会因为你写出难以阅读的代码而批评你。

    如今一切都改用Python了,我确实怀念CPAN,但并不怀念Perl那些半吊子的函数参数。

    然而很长一段时间里,Perl的文档质量远超Python。当时Python的文档几乎专为已掌握Python的人编写。而Perl的文档假设读者时间紧迫、需要立即得到答案,若你读到最后,则假设你或是关心细节,或是迷茫需要更多信息。

    随着数据科学的兴起,Python已经失去了“哦,你应该能猜到,看看这个语法有多么_逻辑_”的优势,变成了“就这样做”。

    • 我发现“perlcritic”非常有用。

      > perlcritic 是一个 Perl 源代码分析器。它是 Perl::Critic 引擎的可执行前端,旨在识别代码中存在的不便、难以阅读、易出错或非传统的构造。大多数规则基于 Damian Conway 的《Perl 最佳实践》一书。然而,perlcritic 并不局限于强制执行 PBP,甚至会支持与 Conway 规则相矛盾的规则。所有规则均可根据个人喜好轻松配置或禁用。

      https://metacpan.org/dist/Perl-Critic/view/bin/perlcritic

      它对我帮助很大。我认为每位 Perl 开发者都应使用它,这可能有助于避免日后出现问题。不过,请谨慎使用“brutal”、“cruel”和“harsh”严重级别。我认为“gentle”在许多情况下都适用。不过,我使用了“brutal”,并且只修复了合法的问题。“brutal”帮助我编写了正确的POD,因为“gentle”不会对此提出异议。

    • > 我以编写可读性强、易于维护的 Perl 代码为荣。

      过去使用 Perl 时,我也做过同样的事情。

      但我逐渐明白 Perl 的一个特点——它的优点也是它的缺点。

      当我使用它时,Perl是我用过的最高级别的语言。它非常表达力强,这意味着我可以将脑海中的想法,以任何语言中最小的阻力在Perl中实现。

      当我与他人合作的Perl代码时,我发现他们非常用心且重视自己的工作。

      但他们的思维方式有时对我来说几乎是陌生的,因此他们表达思想的方式是一种完全不同的 Perl 风格,对我来说可读性要低得多。而且,他们所写代码的哲学理念往往与我所做的恰恰相反。

      现在我日常使用 Python 取代了 Perl,尽管代码的实现似乎与我的思维方式有几分脱节,但别人的代码似乎更容易阅读和理解。(这只是我的个人观点)

      • 正如人们所说,使用 Perl 时,实现同一目标的方法不止一种(TMTOWTDI),而使用 Python 时,只有一种方法。

        两种方法各有其优点。就像在Maven中,我曾在论坛上看到一个问题,有人问“如何做X?”,回复基本上是“你不能这样做,不要尝试,因为那是错误的”。

        • 在Python中,通常也有不止一种方法可以实现。例如,大多数人的Python FizzBuzz实现与我的似乎大不相同:

            def fizzbuzz(n, *args):
              cur = [‘’ for x in range(1,n+1)]
              for m, postfix in args:
                cur = [y+postfix if x%m==0 else y for x, y in zip(range(1,n+1), cur)]
              cur = [str(x) if y == ‘’ else y for x, y in zip(range(1,n+1), cur)]
              return cur
          
            print(“n”.join(fizzbuzz(100, (3, ‘fizz’), (5, ‘buzz’))))
          
          •   国王明智地处决了软件开发人员,
              他们都过上了幸福的生活。
            

            🙂

          • 在 Python 中,应该有一种显而易见的方法来实现它。你的方法显然是个玩笑或是一种异端。

      • 这是一个有趣的观点,如果能用两种语言的示例来阐述会更有趣。

        • 我没有代码示例,但记得:

          – 我在 Perl 中做的很多事情最终都使用了正则表达式

          – 相比之下,Python对正则表达式的支持并非一等公民,因此许多问题会改用字符串函数。(尽管r'<expr>'在引号规则上更少歧义)

          – 在Perl中,路径操作会使用正则表达式

          – 在Python中,我采用了os.path

          – 我会在Python中使用面向对象编程,但在Perl中很少使用

          – argparse

    • > 我不怀念 Perl 那种半吊子的函数参数。

      你的意思是,你不喜欢写类似这样的代码…

          sub foo {
              my ($a, $b, $c) = shift;?
      
      
      • 确实!

        这让我很烦躁,因为我需要检查调用者是否提供了所有必需的参数。这似乎是语言应该做的事情。

        我明白这确实提供了很多灵活性,但Hnnnnnnnnn

        (据我所知,面向对象的Perl并不提供这种灵活性,但我不敢确定,因为我从未真正尝试过。)

        • 面向对象的 Perl 提供完全相同的灵活性。

          如果你有一个名为 “My::Module” 的模块,并且调用 “My::Module->some_method”,那么你应该这样实现:

              sub some_method {
                  my ($pkg, @args) = @_;
          

          即模块名称(作为字符串)作为第一个参数传递。你可以调用

              $pkg->some_other_method;
          

          同样地,如果你有一个对象 “$foo”,你可以调用它像 “$foo->some_other_method”,并实现它如下:

              sub some_method {
                  my ($self, @args) = @_;
          

          即对象作为第一个参数传递。你可以调用 “$self->some_other_method”。

          一个最小的类只是:

              package My::Module;
          
              sub new {
                  my ($pkg, %opts) = @_;
          
                  my $self = bless %opts, $pkg;
          
                  return $self;
              }
          
              1;
          

          别让别人告诉你需要 Moo、Moose、Mouse 或 fields.pm。手动创建对象才是正道 🙂

      •   是的,我讨厌写
        
          sub foo($$$) {
            my ($a, $b, $c) = @_;
          }
        

        其中 @_ 是参数数组,($$$) 是函数原型(预期接收 3 个标量)。

        • Perl 现在支持子程序签名。你可以这样写

          sub foo ($x, $y, $x) { …}

          这只是语法糖,因此你仍然无法传递多个列表,且列表必须是最后一个参数。

      • 不确定你是否故意在这里放了两个 bug 哈哈

        1. shift 只移除第一个元素。

        2. (如果将此归类为 bug)使用 $a 和 $b 是不推荐的,因为它们是使用 sort 时的默认变量。

    • Perl 的函数参数不再需要你进行 shift 操作或访问 @_ 数组。现在甚至有正式的参数签名。核心语言中也在持续改进,以提供一种正确的方式来处理对象,这样你就不需要对哈希进行 bless 操作,使用 Moose、Moo,或 Object::InsideOut(或其他十几个非核心模块)。

      不过,所有旧代码仍然可以正常运行。

    • 是的,我也是这样做的!当我制作 POPFile(100% Perl)时,我非常非常小心,以确保它易于阅读和维护。

    • 也许作为程序员,我们需要集体进行专业防御,只使用 Perl 中的大语言模型 (LLM) 代码。

      当大语言模型(LLM)出现故障时,你需要一个真正的程序员来解决问题。

      但在我看来,大语言模型(LLMs)是代码生成,而代码生成总会在某个时候出现故障,无论使用何种语言,当生成的代码堆坍塌时,都会出现故障。

      未来几年里,大量劣质的企业大语言模型(LLM)代码将被制造出来,这将会非常有趣。

    • 让我猜猜,是MPC吗?

  3. 我希望其他语言也能拥有Perl的taint模式:一旦启用,来自外部的输入会被标记为“tainted”,同时任何你明确标记为tainted的内容也会被标记。如果一个受污染的变量用于填充另一个受污染的变量(例如通过连接),结果本身也会被污染。如果受污染的变量以特定方式使用(例如与`open`调用一起使用),程序会崩溃。清除污染的主要方法是将变量通过正则表达式处理,并使用捕获的匹配结果(这些匹配结果不会被污染)。

    • 这是“解析,不验证”作为语言特性。任何静态类型语言都具备这一特性,即你可以使用一组“未受污染”的领域类型来编写领域逻辑,并仅提供从用户输入到领域类型的安全转换函数(解析器)。

      • 不,它们确实没有这个功能,因为例如你仍然可以使用任意字符串作为文件名来调用 open() 函数,而该字符串可能来自未验证的输入。它们不会强制你将字符串转换为 FileName 类型,同时还要证明你对字符串进行了某种模式匹配。

        • 这是正确的。你需要提供系统函数的替代版本,这些版本只处理解析后的数据而非原始数据,然后禁止使用原生版本。这样虽然多了一些繁琐的步骤,但也能获得更多的灵活性。

          编辑:或许更简单的方法是将输入函数替换为返回 TaintedString 的版本,该类型无法作为普通字符串使用。但相比要求使用安全输入函数,编写一条禁止使用不安全(默认)系统函数的静态分析规则可能更容易,我猜。

        • 现在我设想一个 Rust UncheckedString 类型,带有接受正则表达式的 to_string() 方法。

    • Ruby 支持。对不可信输入的规范化处理并未得到足够的教学或讨论。或者每个平台的正则表达式安全性。

      坦率地说,我认为所有计算机科学/电子工程项目都应要求完成 OWASP 课程,且编码应要求定期继续教育,其中包括为正确性、定义行为和安全性而采用的防御性编码实践。

      • 这在 Ruby 2.7 中被移除了。它很酷,但有点粗糙。

        • 确实,它存在了一段时间。有些人认为 Ruby 是 Perl 的精神继任者,而 Python 常被视为反 Perl。Ruby 的特殊全局变量与 Perl 非常相似。

    • gcc 的 __attribute__((tainted_args)) 非常实用:https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attribute

    • 这在实际中是如何工作的?

      假设 Table 家族在表单中输入了他们儿子 Bobby 的名字。Perl 程序现在内存中有一段“受污染”的字符串 – “Robert'; DROP TABLE Students –”。

      Perl 代码将这段字符串通过正则表达式检查姓名是否有效。姓名可以包含撇号(Miles O'Brien)、连字符(Jean-Luc Picard)以及空格和普通 ASCII 字母,因此正则表达式通过验证,字符串现在不再受污染。

      • > Perl 代码将此字符串通过正则表达式验证姓名有效性

        我认为“解析不验证”在此示例中无助于解决问题,但直观地讲,正则表达式不会验证姓名是否有效,而是“提取字符串中已知安全的所有部分”。

        这对于 SQL 语句而言并不合理,因此有人发明了预处理语句。

        我认为这个想法是,正则表达式解析迫使程序员思考他们对字符串的操作以及未受污染变量的要求。

        例如,文件名字符串不允许包含未转义的目录分隔符、点、换行符、空字节(我可能在这里搞错了大部分细节……),而正则表达式可以移除这些内容或提取子字符串直到遇到第一个禁止的字符。

        当然,这无法完全避免错误。

        但我的想法是,不应使用“safeUserName”这样的变量,而是使用“safeDbStatement”变量。

      • 你应该使用DBI或基于DBI的库来使用预处理语句进行数据库交互。这就是为什么它被称为数据库接口。

    • 我需要了解这个功能的历史。真是令人惊叹。

      附言:啊,这真快 https://en.wikipedia.org/wiki/Taint_checking#History 🙂 (1989)

    • 好主意,谢谢!我认为应该可以让Python对象以类似方式行为(转换为字符串时崩溃/…),需要看看是否能实现。

      在PHP中,可以直接从$_GET/POST构建对象(并清除这些变量以确保它们不会被直接使用),然后依赖数据类型确保这些值不会被错误使用。

  4. 作为一名长期使用Perl和Python的开发者,且两者均在生产环境中使用过,以下是我的看法:

    Perl

    – 从bash切换到Perl非常容易

    – Perl从未给人一种“碍手碍脚”的感觉

    – 写出“只写不读”的代码实在太过容易

    – 不过,我首先学习了Java,大多数人认为我的Perl代码非常易读

    – 正则表达式作为第一类公民非常棒

    – 向后兼容性对仍在运行Perl的旧系统非常有用(比如银行和一些对冲基金)

    Python

    – 强制缩进使阅读他人代码变得容易得多

    – 从一开始一切都是对象,比 Perl 中的 “bless” 功能好得多

    – 缺乏标准的环境配置方式多年以来一直是个问题

    – sklearn 和在大学中教授 Python 真正改变了游戏规则

    • > 缺乏标准的环境配置方式多年以来一直是个问题

      严肃问题:这个问题解决了嗎?我仍然看到一堆选项,其中一些相互依赖,而我笔记本上目前有38个Python二进制文件。标准方法是什么?

      • 没有“法律上的”标准,但uv看起来正朝着成为“事实上的”标准发展。

        • 这很难称之为标准,它只是最近hn rust热潮中的偶像崇拜。

          • 当然,但它显然比 Poetry 更好,而 Poetry 曾经是最好的,直到 uv 出现。

            如果 uv 不是标准,那是因为还没有足够的人尝试过它。它在自己的领域中表现得极其出色。

            • uv 还很年轻,不稳定,而且细节不足。它每月有多次更新,几乎每周都有重大改进和 bug 修复。它还不够成熟,无法成为标准,尽管它已经提供的功能非常出色。但让它成长吧,变革需要时间。

            •    标准
              

              你一直在使用这个词,但我认为它并不意味着你所理解的含义。

            • 虚假二分法。我使用pipenv已有8年。最初它有点太慢,但现在它能完成任务。

          • uv是一款优秀的软件,无论使用何种语言编写。真的,如果你做 Python,值得一试,尤其是脚本模式。

            • 当然,但质量或你的/我的意见并不能使其成为‘标准’,即使未来某天它可能成为标准。

          • 嗯,我不太确定。

            我们没有看到诗歌、pipenv 或 conda(或 hatch 或 PDM,但我从未认为这些工具能达到临界质量)被采用得如此之快。

            这些工具确实很受欢迎,但花了很长时间,而且大多数人发现它们有很多权衡(比 Python 的官方工具好得多,但仍然)。

            我没有在“uv”上看到这种情况。除了对Astral的治理模式的担忧(这可能是合理的!),我没有看到像对poetry那样普遍的“它能用但很难用”的不满。

            再加上uv通过完全消除本地解释器编译的痛苦,持久地解决了对pyenv/asdf/mise的需求,我认为这使得uv在流行度或方法上与之前的工具根本不同。这种“不同”是否等同于“更好”?时间会给出答案。

            关于使用Rust编写?耸肩。对于许多因uv而发生变革的团队来说,他们甚至不知道或不在乎它用什么语言编写。在我看来,使用Rust有两个好处:a) 通过用另一种语言编写管理编程语言环境的工具,避免了“鸡生蛋还是蛋生鸡”的问题,而这种语言b) 不是Bash。

            • > 通过使用另一种语言编写管理编程语言环境的工具来避免鸡生蛋还是蛋生鸡的问题

              我经常听到这种说法,但我不太明白具体用例。似乎人们希望在 Python 中进行开发,希望安装和管理第三方 Python 包,并且知道如何使用命令行工具,但不知何故他们还没有安装 Python,并且会觉得直接安装很困难?在 Linux 上从源代码构建是一个标准的“从系统包管理器获取开发包;配置、编译并安装”流程,我已经做过很多次(是的,将它放在系统 Python 旁边可能会破坏一些东西,但你可以轻松设置一个替代安装前缀,而且无论如何,系统 Python 通常是一个满足大多数开发者基本需求的版本)。在 Windows 上安装是一个标准的 Windows 安装程序体验。

              除此之外,人们似乎会想象 pip 在环境中自我安装的“鸡生蛋还是蛋生鸡”场景。但这是一个已被彻底(尽管效率不高)解决的问题。首先,近三年来 pip 已经能够跨环境安装 (尽管使用了一个丑陋的 hack;我在 https://zahlman.github.io/posts/2025/01/07/python-packaging-… 中详细说明了部分内容)。其次,标准库的 `venv` 默认会将 pip 引导到新环境中——利用预先构建的 Python 包是 zip 存档的事实,以及 Python 有一种从 zip 存档运行代码的协议,而 pip 包实现了该协议。

              我听说过的真正引导问题是 https://github.com/pypa/packaging-problems/issues/342,但这影响的人非常少——基本上是那些希望“从源代码构建”整个 Python 工具链的 Linux 发行版维护者,尽管这些代码本可以由运行时按需进行字节码编译。

            • 无论你是否喜欢,无论它是否更好,它都不在标准库中,也不是绝大多数人安装 Python 库的方式。

          • 你忘了更新你的 HN 流行列表。Zig 流行,Rust 过时了。

          • 不,不是。我看到的地方,uv 都被采用。

            • 我们已经进入 uv 炒作周期的第一年。它需要足够的时间来确保它解决了前辈的问题。

              那么,如果 uv 随处可见呢?Poetry、pipenv 等也是如此。给它时间。

              • 尝试过所有这些,都放弃了。坚持使用 UV,我愿意冒险一试。

            • 我在使用 UV,但在企业环境中只看到 Conda。

        • 是的。尝试 UV,然后就不要回头了。

        • uv用于项目管理,pipx用于用户级/系统级工具安装。

        • Astral 的商业模式是什么?

      • > 严肃问题:这个问题解决了嗎?

        这取决于“设置”的具体含义。

        在Python二进制文件已安装的情况下,创建环境非常简单(自2012年底以来就是标准库功能)。选择使用哪个环境也同样简单。安装预编译包也很容易,甚至遗留的源代码包也相当简单(但速度较慢,且安装过程会运行任意代码,而这些代码完全没有必要)。即使是依赖项解析通常也不算太糟糕。

        真正的问题在于

        * 本地从源代码构建多语言包,因为这需要设置临时本地构建环境(而构建工具必须避免在此处发生递归)

        * 使用外部非 Python 依赖项(本质上尚未解决,大家通过将依赖项打包或不声明依赖项并在运行时失败来绕过此问题)——参见 https://pypackaging-native.github.io/ 了解问题概述,以及 https://peps.python.org/pep-0725/ 了解他们试图标准化以解决此问题的方案

        * 处理源包的元数据;在非常一般的情况下,你需要编译源代码才能获取这些元数据(尽管包构建 API 现在提供了一个钩子,使构建后端可以专门准备元数据)。这是因为某些包的依赖关系依赖于非常特定的平台细节,而这些细节似乎无法通过标准元数据中的“环境标记”方案来表达(https://peps.python.org/pep-0508/#environment-markers)

        * 当然,确定哪些包需要包含在你的环境中(Python 不会为你决定直接依赖项是什么)以及随时间管理该环境。所有这些其他工具出现的原因是,Pip 仅负责安装包并提供基本的环境检查功能;它现在才开始处理锁定文件,例如,现在终于有了它们的标准(https://peps.python.org/pep-0751/)。

        但如果你指的是是否存在一个由核心语言开发者正式认可的、能够“包揽一切”的标准工具链,那么答案是否定的,你永远不应期待这种工具链的存在。对于“一切”的具体含义,各方并未达成共识,而 Python 用户(其中很大一部分并不符合传统意义上的“开发者”形象)在工作流程和哲学/美学偏好上存在巨大差异。此外,核心语言团队通常不会关注或解决这个问题;他们首先关心的是解释器。打包问题只是次要考虑因素。好消息是:Python 包装权威机构(这个名字完全不具权威性,而且是开玩笑起的,但很多人没明白这一点)正在积极推进官方治理工作(参见 https://peps.python.org/pep-0772/)。

        > 截至目前,我的笔记本电脑上有 38 个 Python 二进制文件

        这肯定出了问题(除非你在 Windows 上,因为创建符号链接需要管理员权限,而默认情况下 `venv` 不会尝试这样做)。明确一点,我指的是你的环境配置,而不是工具本身。你应该只为每个不同的 Python 版本使用一个环境。如果你愿意发邮件给我(我使用Proton服务,用户名与这里相同),并提供当前环境的详细设置以及你试图实现的目标,我很乐意尝试帮助你。

    • > – 多年来缺乏标准的环境设置方式确实令人困扰

      我必须说,与多年使用 Perl 的经历相比,Python 通过标准库提供了令人耳目一新的“开箱即用”功能。

      我的代码很少需要“外部帮助”,通常只是像requests或numpy这样的库。

      我怀疑这是因为我将Python与Perl在同一环境中使用,用于自动化Unix风格的任务。

      我怀疑“设置环境”的问题是因为Python过于成功,已成为一种极其广泛的通用语言。

    • Perl是我第一门脚本语言,我偶尔需要运行一些旧脚本(15-20年前的),它们总是能正常运行。Python脚本的寿命是6-12个月。

      • 所以,如果你把工作保障放在首位,…

      • > Python 脚本只能维持 6-12 个月。

        如果你知道自己在做什么,就不是这样。

        • “你拿错了” 😉

          • 每个 Python 版本都官方支持 5 年。大量有用的脚本无需依赖标准库之外的任何组件,我有很多年前的代码从未受到标准库废弃功能的影响(这些废弃功能其实都位于相对不显眼的角落),在当前 Python 版本下仍能正常运行。(当然,我作为 3.x 版本的早期采用者,这也有帮助。) 相反,我今天编写的代码通常应向下兼容至3.6(f-字符串非常实用,而pathlib的语义在该版本中得到了显著改进)。

          • 我的意思是,如果你无法通过使用流行的包管理器(如Poetry或uv)创建可重复的虚拟环境,那么是的,你使用方式有误。如果你仅依赖 requirements.txt 固定版本而不处理传递依赖关系,那么是的,你搞错了。这种情况下属于技能问题。

            • > 如果你仅依赖 requirements.txt 固定版本而不处理传递依赖关系,那么是的,你搞错了。

              即使如此,如果你仍然拥有原始环境,你可能根本不需要重新创建它。如果你确实需要为较新的 Python 版本创建一个等效环境(Python 的已终止支持版本并不会凭空消失,但也许你升级了系统,或者更重要的是,你正在提前为这种情况做准备),那么你通常可以轻松地从旧环境中创建所需的 requirements.txt 文件(或者,说到底,一个 PEP 751 锁定文件)。

    • 那些贬低某种语言的文章往往带有过时的非此即彼的视角。

      大多数语言都有一个或两个不错的框架,因此在不同用例中使用它们的差异可能比许多人想象的要小,而非我们通过道听途说得知的所谓“新潮流”。

      在许多语言中都可以制造混乱,而且很久以前甚至更容易做到,只是其中一些代码正常工作且长期未被修改。

      • 工具箱与宗教狂热。有时,你不得不维护.bat文件、Tcl、F77或COBOL。专业人士不会抱怨或皱眉,而是完成工作。

    • 我从未做过太多Perl,设置Perl环境的标准方式是什么?CPAN?

  5. 暂且不提语言设计问题和其他语言的兴起,思考 Perl 失去流行度的其他原因也颇有趣味。你们中有些人比我更了解这段历史,但我认为现在大多数 HN 读者对此已不甚了解。

    我认为最大的原因是 Larry Wall 等人坚持从 Perl 5 到 Perl 6 的自下而上“社区”过渡。Perl 6的设计过程于2000年在一次Perl大会上宣布[1];15年后,几乎所有Perl用户仍在使用Perl 5。Perl社区无法及时集体推进这一进程,应被其他语言社区视为警示案例。

    蒂姆·奥莱利(Tim O'Reilly)还提出了一个可能同样重要的次要观点。长期以来,Perl书籍是奥莱利出版社的畅销书。但这些书籍的作者并未采纳他关于撰写一本“Perl for the Web”(实际上是Perl for CGI)书籍的建议。此类书籍最终问世,但领先作者拒绝撰写此类书籍可能为PHP的崛起提供了便利。

    [1] https://en.wikipedia.org/wiki/Raku_(programming_language)#Hi

    • 当大多数想使用Perl的人已经熟悉shell、sed、awk和C时,Perl就是完美的语言。

      它成功是因为它是这些工具/语言的美丽而可怕的结合。如果你熟悉这些东西,Perl真的很容易拼凑起来生成网页或用于自动化管理任务。

      考虑到拉里·沃尔的教育背景,或许我们不应惊讶于 Perl 从皮金语[1] 演变为克里奥尔语[2] 的语言进化过程。

      我接触 Perl 稍晚一些,当时并非 Unix 的超级熟练用户,且仅在学校学习过 C 语言。我将自己归类为 Perl 开发者中属于 Perl 发展第二阶段“克里奥尔语言”时期的群体。通过学习 Perl,我掌握了大量 Unix 知识并提升了 C 语言技能。

      尽管 Perl 的混合特性使其取得成功,但当网络开发领域扩展到更多缺乏必要背景以充分利用这种混合特性的群体时,它从优势变成了障碍。所有这些语法从令人熟悉变得诡异。一个完美的例子就是文件测试运算符[3])。

      Perl 6 的发展困境无疑加剧了网络开发社区变化带来的挑战。它们制造了足够的不确定性,导致大量人自问:“既然 Perl 6 即将问世,为何还要学习 Perl 5?”这在 2001 年至 2010 年间阻碍了 Perl 的采用,而 Python 和 Ruby 则迅速崛起。

      Rakulang 有一种魔力。编写它就像使用外星人赐予我们的语言。我希望它能获得更多采用,因为编写它既有趣又能真正开拓思维。

      最终,我认为社区性质的转变是 Perl 衰落的主要因素,而非 Perl 6 的缓慢推出及其宣传失败。

      我仍然热爱编写 Perl 5,并希望能够更多地使用它。

      [1] https://en.wikipedia.org/wiki/Pidgin [2] https://en.wikipedia.org/wiki/Creole_language[3] https://perldoc.perl.org/functions/-X

      • Perl 6 确实吸走了社区中的所有前进动力。

        它已成为如何_不_进行重大转型的典型案例。

        KDE3/4、GNOME 2/3、Python 2/3 的转型都从这一教训中受益(尽管它们自身仍在经历许多痛苦)。

        Raku 可能是一种有趣的语言(我还没深入研究过),但它不是 Perl。Larry 等人本应从一开始就将其独立出来,让其他人继续传承 Perl 的精神。他们这样做太晚了,当时的势头已经消退。

        Perl 5 是那个时代的产物,但 Linux、C、Python 2 或 PHP3 也是如此,而它们至今仍具有重要意义。

    • 在公司切换到 Python 3 之前,我积累了大量 Perl 5 的编程经验。

      > Perl 社区未能及时集体推进发展的能力,应被其他语言社区视为一个警示案例。

      我认为这是一个我之前未曾考虑过的观点。

      我认为 Perl 已经无法吸引新用户。总会有用户离开。如果他们没有被替换,你将逐渐萎缩。

      我认为你提到的这一点是他们无法吸引新用户的原因之一。我认为人们会问自己“既然我知道 Perl6 推出后需要重写,为什么现在要选择 Perl?”并认为 Perl5 是糟糕的选择。我认为 Perl 因其“丑陋、难以理解、只写噪音代码”的声誉,让人们甚至不考虑使用它,即使这种声誉与实际生产代码库不符。

    • 我不得不确认它是否存在,因为我确信自己有一本O'Reilly在90年代末出版的专注于Perl的CGI书籍,果不其然,我拥有的那本书出版于1996年(2000年推出了第二版)。

      我不是说你的轶事不准确,但当时我的印象是《24小时学会PHP》比O'Reilly的Perl书籍要热门得多——这可能只是运气、营销、更吸引人的书名,或者PHP本身更适合人们想要学习和做的事情。

      • 在HTML文件中嵌入PHP标签,相较于Perl的编程方式,是一种更自然的“由外而内”的网络编程入门方式。如果你已经掌握一些HTML知识,并希望在页面中添加一个小工具,PHP能让这一过程变得异常简单。

        • 此外,你可以直接通过FTP将文件上传到托管服务器,它就会神奇地运行。我所知道的其他语言当时都不允许这样做。

          • 现在这似乎已成为失传的技艺。不过在本地运行则是另一回事。

      • 是的,这就是我所想的。1996年还处于早期阶段——但或许正是这种延迟让PHP在网络发展的早期阶段获得了比其他语言更稳固的立足点。

    • 从Perl5到PHP3的过渡。我认为PHP胜出的原因如下:1. 更易于配置。2. 更统一的环境,这意味着在当时的各种主机上部署更轻松。3. 更安全(虽然只是稍微安全一些)。4. Unicode 实际可用。5. 语法更加逻辑化:无需每次在需要比一维哈希或数组更深的数据结构时都使用 man perldsc[0]。6. 语言特性如标量,使编程更轻松。7. 通常文件更少……它设计为嵌入 HTML 而不是生成 HTML。

      [0] https://perldoc.perl.org/perldsc

      • 我从 Perl 切换到 PHP 主要是因为 PHP 执行速度快得多(无需处理像 modperl 这样的复杂配置),而且我喜欢那些内置的便利函数,比如“strtoupper”和日期格式化功能!

    • 我认为Perl的衰落源于三个因素的综合作用:

      1. 其他网络语言的崛起,这些语言在Perl擅长的领域表现得更好。

      Perl可能是一门适合系统管理员进行文本处理的优秀语言。随后,它凭借Apache和mod_perl成为首批网络语言之一,但它在这一领域或许从未真正出色。一旦PHP、Python、Ruby和(最终)JavaScript出现,Perl在大型可维护代码库方面的显著缺陷使其难以竞争。

      在许多情况下,一种新的、更好的语言无法取代一种旧的、根深蒂固的语言。旧语言拥有生态系统,用户真的不喜欢重写程序,这赋予了它显著的竞争优势。

      但在网络早期崛起时期,新代码的编写量如此之大,这种优势逐渐消退。在互联网泡沫时期,数千家初创公司涌现,数百万行全新代码被编写。在这种罕见的空白市场环境中,新语言拥有更公平的竞争环境。

      1. Perl 6 正在抛弃其用户。

      作为语言维护者,我深知打破过去、这次一定要做对的渴望有多强烈。我维护的语言(Dart)与 Perl 相比相对较新且没有缺陷。因此,我不能完全责怪 Wall 将 Perl 6 视为一张空白支票,用来尝试天下所有新点子。

      但问题是,你对语言做的改动越多,你就越会与用户及其程序疏远。如果他们无法跟上你的步伐,你们双方都会失败。他们将失去对核心工具的主动维护者,而你将失去他们为构建和维护 everyone 依赖的包生态系统所付出的所有努力。

      一辆赛车如果抛弃了燃料箱的全部重量,可能会跑得更快,但这种速度不会持续太久。

      我认为Perl 6/Raku的开发者们过于热衷于创建一种新语言,以至于忘记了带上他们的用户。他们冲在前面,把用户抛在了后面。

      1. 一种极具动态性的语言。

      如果你想在演进语言的同时保持生态系统的完整性,那么所有代码都需要不断迁移到新语言的语法和语义中。手动迁移是噩梦般的昂贵。看看 Python 3 吧。

      如果能通过工具自动完成大部分迁移工作,情况会好得多。为此,工具必须能够通过静态分析详细推断程序的语义。你不能依赖动态分析(即运行代码并观察其行为),因为它不够全面,无法安全地用于大规模源代码更改。

      显然,静态类型在这方面帮助很大。Perl 5 不仅没有这些类型,而且你甚至无法在不运行 Perl 代码的情况下解析一个 Perl 程序。这是一种极其难以静态分析和理解其语义的语言。

      因此,即使 Perl 6 团队希望将 Perl 5 的生态系统带入其中,这样做也将极具挑战性。

      我本可以将此视为编程语言悲剧的案例研究,但坦白说,我甚至不确定这是否是一件坏事。或许编程语言本就应该有一个生命周期,最终被其他语言完全取代。也许 Perl 的时代已经结束。

      我对 Perl 6 和 Raku 开发者所做的创新工作深表感激。这是一种编程语言理念的宝库,其他语言将在未来几十年里不断借鉴。

      • 回复 #1:

        Perl 不仅仅有 mod_perl。它还拥有与 Ruby 和 Python 同样优秀的框架,使之成为 Web 开发领域的佼佼者。这个框架名为 Catalyst,其生产就绪时间与 RoR 和 Django 几乎同步。

        在我看来,Perl 在这一领域失败的真正原因在于,该语言定义嵌套数据结构的操作极为不友好。在 JavaScript、Ruby 和 Python 中,字典列表只需使用类似 JSON 的语法:{ “x”: […], “y”: […] }

        而在 Perl 中,你必须处理标量、引用、标量引用、值引用等,而且符号的含义会根据变量内容的不同而变化。我的意思是,我花了很多时间编写 Perl 代码,但从未弄清楚这一点。

        在一个你只想实现 CRUD 操作来加载/保存结构化数据的世界里,那些让你能够操作数据并保持理智的框架才是赢家。

        • 是的,语法通过符号进行“词法类型化”,而语言本身又不进行静态类型检查,这简直是两全其美的糟糕结合。

        • Catalyst、Dancer 和 Mojolicious 实际上都存在且已存在一段时间。它们都支持 PSGI。

          Mason 在这些之前就已存在。

          还有其他不太流行的选项,这在 Perl 的任何特性或模块中都很常见。

        • 我记得在 80 年代末尝试编写一个 Perl 程序时,曾遇到过 exactly 那个问题,当时我愚蠢地用 Lisp / PostScript(后来是 Python / JavaScript / Ruby)的多态数组和普通对象引用来设计这个程序。

          我对 Lisp 和 PostScript 引用以及 C 指针的工作原理有清晰简单的概念模型,但当我思考 Perl 时,这些概念反而误导了我,让我感到困惑和失望:

          https://donhopkins.medium.com/the-shape-of-psiber-space-octo

          当我坐下来尝试用 Perl 实现这个简单直观的设计时,我突然意识到,你无法对没有名称的事物进行引用,而 Perl 的基于名称的引用,尽管它们伪装成 C 或 C++ 的“&”语法(用于获取对象的地址),实际上是完全不同的东西。

          Perl喜欢从其他语言(通常是像bash和awk这样的糟糕语言)中挑选和融合语法,可能是为了“帮助那些熟悉该语言的人更容易学习Perl”,但它完全忽略了语义,这实际上让学习Perl变得困难得多,因为“&”看起来像C,但行为完全不同,而且更加局限和古怪。

          你不需要将 C 值赋给全局变量才能获取其地址。

          语法和符号的选择并不是学习一门语言的难点,如果你搞错了语义,仅仅模仿另一门语义正确的语言的浅层语法,只会让人感到困惑和失望。

          当你随意混搭多种设计糟糕的语言的“语法糖”,将其拼凑成一锅语义奇异、杂乱无章的“人工甜味剂”时,你得到的便是“吐根糖浆般的语法”。

          Perl 5 之前(Perl 4 及更早版本):

          引用纯粹是符号性的,基于类型全局变量和包变量名称。你只能别名或引用存在于符号表中的变量;无法获取字面量或临时值的指针,也无法在严格模式下对词法(my)变量进行引用。这使得嵌套或无名数据结构在不进行大量手动记录的情况下几乎无法实现。

          Perl 5.0(1994年10月)——硬引用和匿名结构:

          Perl 5 终于通过反斜杠操作符() 和匿名数据构造器引入了真正的第一类引用:[ … ] 用于数组,{ … } 用于哈希。这让你可以编写如下代码:

            my $tree = { name => “root”, children => [ { name => “leaf” } ] };
          

          无需为内部哈希或数组指定全局名称。

          显式解引用、上下文敏感性和自动创建:

          即使使用硬引用,仍需显式解包($ref->[0], $href->{key}),而 Perl 的上下文规则(标量 vs. 列表 vs. 空值)仍可能令人困惑。Perl 的自动创建功能(在首次解引用时自动创建嵌套哈希/数组)简化了一些冗余代码——但可能让习惯更显式模型的初学者感到意外。

          Perl 与 Lisp、PostScript、JavaScript、Ruby、Python 等的比较:

          Lisp:列表由 cons 单元构建,可直接作为一等值进行操作,例如 (list 1 2 (list 3 4))。

          PostScript:数组([1 2]) 和字典(<< /Key (Value) >>)是字面量形式的嵌套结构,无需单独的指针语法。

          JavaScript/Ruby/Python:均提供 JSON 风格的字面量([1,2,[3,4]], {“x”:1,“y”:[2,3]}),并允许直接嵌入嵌套结构,无需在顶级容器之外使用反斜杠或符号。

          由于从一开始就没有正确处理引用,然后在接下来的几十年里不得不依赖实验性 hack 和事后添加的语法负担来弥补最初糟糕的设计,Perl 做出了一些权衡,这些权衡所带来的成本远高于它们试图解决的自我造成的问题的节省。

          碎片化的语法:多种解引用形式和功能受限的调整(后缀解引用、自动生成 pragma)将 Perl 分裂成行为不一致的拼凑体。

          意外的副作用:自动生成可能悄无声息地创建大量未使用的数据结构,导致隐藏的内存/性能开销。

          微妙的错误:上下文敏感的规则(何时自动生成,何时不自动生成)仍然是常见的陷阱,即使对于资深的 Perl 开发者也是如此。

          兼容性拖累:同时支持旧版 5.x 版本和现代功能迫使开发者进行额外的版本检查、冗余代码和警告抑制。

          认知开销:处理反斜杠、符号和多种解引用风格需要比 Lisp 风格或 JSON 基于语言的统一列表/映射语法更碎片化的思维模型。

          “这里未言明的右脑约束是:解决设计问题引入的复杂性必须与问题的的重要性成正比。”——Guido van Rossum

          编辑:当然,Perl 最终几乎原封不动地模仿了 JSON 风格的字面量语法,但仍保留了旧有的不良语义,而要实现这一目标,你仍然必须应对深层复杂性:

          功能受限的语法:新的解引用形式(后缀、切片)需要 pragma 或更高版本的 Perl。

          自动创建意外:嵌套查找可能会静默创建未使用数据,导致内存膨胀。

          多种解引用风格:反斜杠、大括号、箭头和符号——每个都有自己的上下文规则——会破坏你的思维模型。

          兼容性支持:要在<5.24版本上运行,你需要版本检查、关闭警告,或完全避免使用现代语法糖。

          隐藏的复杂性:在类似 JSON 的字面量之下,隐藏着一团迷宫般的符号、上下文和边界情况行为——这与 Lisp / PostScript / JS 的统一简洁性相去甚远。

          “许多,如果不是大多数”是不够的,因为边界情况总会回来咬你。你不能只是在泰坦尼克号上重新安排甲板椅,就期望船不会沉没。而它确实沉没了,很久以前。

          • > JavaScript / Ruby / Python:均提供 JSON 风格的字面量([1,2,[3,4]], {“x”:1,“y”:[2,3]})

            Perl 的语法与此类似:

            [1,2,[3,4]], {“x”, 1,“y”, [2,3]}

            也可以用一些语法糖来写:

            [1,2,[3,4]], {x => 1, y => [2,3]}

            对于大多数情况而言,给定一个 Perl 数据结构,从 Perl 到 JSON 再到 Perl 的转换过程是透明的。

          • > 我突然意识到,你不能引用一个没有名字的东西

            不过这并不正确。

            • 请阅读我写的内容:

              >我记得在80年代末确实遇到过这个问题[…]

              告诉我我写了什么是不正确的。Perl 5直到1994年10月才发布。

              在Perl 4中,符号别名通过类型全局变量实现,且无法获取字面量、临时变量或词法变量的地址。

              即使在 Perl 5 中,引用仍需要复杂的语法,伴随大量意外副作用、边界情况、隐蔽 bug、多种形式、上下文敏感规则、自动生成 hack、内存开销与浪费、隐蔽陷阱,且其复杂度和使用难度远超其他语言中的引用机制。

      • > 但问题是,你对语言做的改动越多,你就越远离你的用户和他们的程序。如果他们无法跟上你,你们都会失败。

        人们是否应该不再创建新语言?

        新语言是否不应与现有语言有深层相似性?

        > 手动迁移是噩梦般的昂贵。看看 Python 3。

        > 如果能通过工具自动完成大部分迁移工作,情况会好得多。

        事实上,Python一直有丰富的工具支持这一过程。随Python发布的`2to3`脚本及其对应的`lib2to3`库曾是标准库的一部分,直至3.11版本。第三方`six`兼容性库至今仍从PyPI下载的频率高于NumPy。

        > 要实现这一点,工具需要能够通过静态分析详细推断程序的语义。

        从我所见,这些工具用户的实际体验并不一致。它们在某些地方会生成丑陋的代码,但通常能通过测试。是的,手动修复通常是必要的,但在那个时代确实存在一些源代码包(而且它们也没有从 PyPI 上消失),这些包会在 `setup.py` 中检测 Python 版本,并在安装时根据需要运行工具,从而让用户满意。

        • > 是否应该不再创建新的编程语言?

          应该,但他们应该明白,当他们这样做时,要获得广泛采用非常困难。不是不可能,但非常困难。

          _> 事实上,Python中对此有丰富的工具支持。随Python附带的`2to3`脚本和相应的`lib2to3`是标准库的一部分,直到3.11版本。第三方`six`兼容性库从PyPI的下载量至今仍高于NumPy。

          是的,即便如此,所有参与者都清楚这次迁移耗时极长,需要大量人力,且在多年间一直是重大难题。

          Python 3的开发始于2006年,而Python 2直至2020年才正式停用[1]。为了更好地理解这一点,Python 社区在迁移到 Python 3 上花费的时间几乎与 Python 在此之前整个历史中花费的时间相当。(2006 年 Python 已经 15 岁了,而他们花了 14 年时间才废弃 Python 2。)

          你还会发现,最容易自动化的更改要么是词法上的(重命名核心库方法),要么是语法上的(将 print 改为 print()),而最困难的更改涉及值类型的变化(字符串)。

          静态类型使得代码的自动迁移变得容易得多。

          [1]: https://www.python.org/doc/sunset-python-2/

      • Python 的灵魂是“Pythonic”,从 Python 2 到 Python 3 都保持了纯粹,但 Perl 的灵魂是“Pearl-ick”,而 Perl 6 的“ick”与 Perl 5 完全不同。

        Perl 的语言设计痴迷于解决一个又一个自我设定的难题。

        https://www.artima.com/weblogs/viewpost.jsp?thread=147358

        语言设计不仅仅是解决谜题

        作者:Guido van Rossum,2006年2月10日

        摘要:今天在python-dev上发生的一件事让我再次意识到,语言设计不仅仅是解决谜题。一篇关于Pythonicity本质的漫谈,最终将语言设计与用户界面设计进行了比较。

        有些人似乎认为语言设计就像解谜一样。他们根据一组需求系统地搜索解决方案空间,找到匹配项后便声称找到了完美的语言特性,仿佛解出了一道数独谜题。例如,今天有人声称解决了多语句lambda的问题。

        但这样的解决方案往往缺乏“Pythonicity”——一个好的 Python 功能所具备的难以捉摸的特征。Pythonicity 无法用硬性约束来表达。即使《Python 禅》也无法转化为对 Pythonicity 的简单测试。

        在上面的示例中,很容易找到所提解决方案的致命弱点:双冒号虽然在语法上确实不ambiguous(这是“拼图约束”之一),但完全是任意的,且与Python中的其他任何内容都不相似。双冒号在另一个地方出现,但那里它是切片语法的一部分,其中a[::]只是扩展切片表示法a[start:stop:step]的退化情况,其中start、stop和step都被省略。但这与提案中的lambda <args>::<suite>完全不相似。双冒号在其他语言中的用法也没有类比——在 C++(和 Perl)中,它是作用域运算符。

        然而,这并非我拒绝该提案的原因。如果双冒号不符合 Python 风格,或许可以找到一种使用单个冒号且仍向后兼容的解决方案(这是 Pythonic 谜题解决者面临的另一个重大约束)。我实际上已经想到了一个方案:如果冒号后有文本,则为向后兼容的表达式lambda;如果为换行符,则为多行lambda;提案的其余部分可保持不变。瞬间搞定,证明完毕,大功告成,等等。

        但我同样拒绝这个方案,因为最终(这也是我承认自己无意中误导了提交者之处),我认为任何在表达式中间嵌入基于缩进的代码块的解决方案都是不可接受的。由于我认为替代的语法(如大括号或 begin/end 关键字)同样不可接受,这基本上使多行 lambda 成为一个无法解决的难题。

        我喜欢这种状态!某种程度上,我之所以花大力气描述在表达式中嵌入缩进块的问题(从而无意中设下陷阱),是为了传达这个问题的不可解决性。我本应更了解我的极客受众,并预料到有人会解决它。 🙂

        这里未言明的、右脑式的约束是:解决设计问题所引入的复杂性必须与问题的的重要性成正比。在我看来,lambda 无法包含 print 语句或 while 循环等只是一个小缺陷;毕竟,你可以直接使用当前作用域内嵌套的命名函数。

        但对我来说,任何针对这个谜题的解决方案的复杂性都极其巨大:它要求解析器(更准确地说,是词法分析器)能够在缩进敏感模式和缩进不敏感模式之间来回切换,并维护一个之前模式和缩进级别的栈。从技术上讲,这些问题都可以解决(已经存在一个缩进级别的栈,可以进行泛化)。但这些并不能消除我内心深处认为这只是一个复杂的鲁布·戈德堡装置的感觉。

        数学家并不介意这些——证明就是证明,无论它包含2步还是2000步,无论它需要无限维空间来证明关于整数的事物。有时,软件的等价物也是可以接受的,基于“目的正当化手段”的理论。谷歌的一些惊人成就也具有这种性质,尽管我们竭尽全力让它看起来简单。

        问题就在这里:无法让鲁布·戈德堡式的语言特性看起来简单。编程语言的特性,无论是语法还是语义,都是语言用户界面的组成部分。而用户界面只能处理有限的复杂性,否则就会变得无法使用。这也是为什么Python永远不会有延续,甚至为什么我对优化尾递归不感兴趣。但这将是另一篇文章的内容。

  6. 从技术上讲,我在80年代作为孩子时就开始编程了。我上大学是在90年代。我确实学习了Perl并使用过它。

    然而,我必须说,我身边的许多专业人士早在90年代就认为Perl有问题。那时它在学术界已经受到轻视。也许在IT部门或数学部门不是这样,但在计算机科学部门就是这样。它被IT人员、质量保证人员以及那些将工具拼凑在一起的人使用。很多人认为它不适合用于严肃的生产代码,或者任何需要长期维护或由超过1人的团队开发的项目。你对它的看法肯定取决于你当时所处的位置以及你如何接触到它。如果你所在的团队正在开发用于销售的软件,涉及大量人员,并且有版本控制和质量保证等流程,那么Perl可能就不是你的菜了。

  7. 我在2000年代中期使用Perl工作了大约2.5年。这门语言并不适合我,但我喜欢、尊重,并且至今仍与那些热爱它的人保持着友谊。然而,我始终对这样一个事实感到震惊:他们中没有人能够,甚至不敢断言自己能一眼看懂大多数代码片段的功能,即使这些片段只使用了基础语言的构造。当他们处理现有代码时,会运行代码、调整代码、再次运行,可能将部分代码提取到小文件中观察其行为,查阅perldoc文档,在IRC上提问等。作为一名Lisp开发者,我支持交互式与迭代式开发,但我也喜欢学习工具以便随着时间推移更高效地使用它们。我发现学习 Perl 并未让我在使用它时变得更高效(在规模适中的现有代码库中,该代码库既需要维护又需要开发新功能),而我认识的 Perl 爱好者似乎也不介意工作中不包含这一部分。

    无论如何,在我离开那里之前,我不得不面试候选人。因为我认为上述方式就是使用 Perl 的工作方式,我开始问那些声称会使用 Perl 的人:“反转内置函数能否反转一个列表?”(我不会剧透答案。)大多数人会回答“是”或“否”;其中 75% 的人回答错误。无论如何,我都会问他们:“假设你对这个答案没有把握。你会如何确定真相?”据我所记,90%的人会说“我会写这段一行代码……”而(我发誓)100%的一行代码都会让任何理性的人觉得这是一个错误的答案。那些说“我会查阅perldoc”的人才是我批准参加后续面试的唯一对象。

    • 我讨厌那种无法通过阅读代码就理解其功能的代码。我想说,我写的代码中大概有99%都体现了这一点,我拒绝在任何可能的情况下使用复杂的语言结构,即使这会让代码变长。

      当我还是个孩子刚开始工作时,我经常会用最初想到的代码来编写,但三个月后再回头看,你不得不把整个代码扔掉,因为它无法维护或添加。

      另一方面,有时语言的某些新增功能实在太过实用,不得不扩展自己的语法库。例如在C#中就发生过几次。其中一个值得注意的新增功能是LINQ,它极大简化了数据操作。但这同样可能带来风险,就像复杂的数据库存储过程一样。

  8. 许多人在这个帖子中推测Raku(原名“Perl 6”)杀死了Perl。但我尚未看到令人信服的第一手资料来证实这一点。

    我当然不相信这一点。当时我接触过的所有使用 Perl 的人都清楚它不会消失:人类已经将互联网的基础设施过多地依赖于它。即使 Larry 的新实验取得巨大成功,也有人必须继续维护它多年。(当时人们似乎对这个实验持怀疑态度,仍留在 Perl 5 阵营,等待看到实验结果再决定是否关注。)

    我仍然难以理解为什么 Perl 失宠[1],但我认为另一位评论者在这里写的内容可能接近真相:对于熟悉 shell、C、awk、sed、Vim 等的 Unix 用户来说,Perl 是自然的扩展。然后出现了一代在 … 我不知道,Visual Basic 和 Java?而这些人更倾向于像 Python 这样的语言,后者最终流行到成为下一代的入门语言。

    [1]:了解我的人或许能明白:https://entropicthoughts.com/why-perl

    • > 我当时接触过的所有使用 Perl 的人都认为它不会消失

      但那些没有使用 Perl 的人,或者只是将其作为副业的人呢?我个人在 2000 年代初就推迟了对 Perl 5 的深入学习,因为我期待着“Perl 6”的到来。奥斯本效应是真实存在的。

      EDIT 或者,公司启动重大新项目时,决定使用哪种语言编写?说“Perl 5将长期得到支持,我们无需将现有项目迁移出去”是一回事。但说“我们想启动一个新项目;应该用 Perl 5 开始吗?它将在一年或两年后成为‘遗留’语言,当 Perl 6 发布时?还是应该用 Python 编写?”

      https://en.wikipedia.org/wiki/Osborne_effect

    • 有许多利刃让Perl社区流血:

      1. 企业开发

      Java 等技术导致了一代开发者逐渐远离内核和 shell。该领域的专业化导致了更高的专业化程度,大多数开发者与运行软件的部署和管理关联度降低。

      工具也变得更加完善,减少了对胶水代码的需求,并将胶水层转移到配置文件或平台特定语言中。

      后来,DevOps 取代了系统管理员,云计算环境中 Perl 的应用空间大幅缩小。

      2. Python 的崛起

      我认为这主要归功于大学教育。Perl 设计上非常表达力强,而 Python 据说只有“一种正确的方式来做”。想象一下,如果你是一名助教,需要批改一百份代码提交;在 Python 中,大家可能都以三种方式之一编写代码,而在 Perl 中,可能性是无穷无尽的。Perl 是一种用于编写而非阅读的语言。

      3. 网络安全成为重要议题

      这再次与可读性和可测试性相关。安全需求开始受到重视,而 Perl 并未为此设计。

      4. 网页开发被 Rails、PHP 及 SPAs 取代

      我对具体原因不太清楚,但 Perl 无法与新兴网页技术竞争。

      • 你可以用 Perl 编写高质量的安全代码,但实现中的动态性水平以及仅有一个主要实现的事实意味着静态分析的质量难以保证。

    • 我同意“对于熟悉 shell、C、awk、sed、Vim 等的 Unix 用户来说,Perl 是自然的扩展。随后出现了一代在 Visual Basic 和 Java 等环境中成长的程序员,他们更倾向于选择 Python 之类的语言。”

      我也相信这一点。

      我不使用Python。我更愿意使用Perl (!)、Tcl、Lua (!)、Go (!)、C (!)、OCaml、Erlang/Elixir,以及Factor/Forth,非常少用Common Lisp(SBCL)。我不喜欢Java/Kotlin及其相关语言。不过,我最初是从shell脚本开始的,然后可能接触过一点Perl和Tcl,而且经常使用C,因为在我还是个孩子的时候,我正在修改用C编写的ioquake3分支。

    • 作为一名在21世纪初从大量使用Perl转向大量使用Python的人,这是因为Perl中那些让它非常适合系统“考古开发运维”脚本编写的快捷方式,使得阅读他人代码和编写超过几个文件的程序变得困难。我仍然大量使用grep、awk、sed、cut等工具,只是不再使用Perl。

      我不会说我是用Visual Basic长大的。这并不是一种教授结构化编程的语言。

    • 更好/更少糟糕且更易于访问的语言杀死了Perl。而我这么说,是因为我对POSIX sh/awk/sed相当熟悉;这意味着在使用它们时,我对无处不在的UNIX脑残设计感到厌恶。

      UNIX 开发者之后推出 Plan 9 绝非没有原因,让我告诉你。

      • “看起来像 sh/awk/sed”并不是 Perl 传道者认为的重大优势。恰恰相反!

        真正使用过sh/awk/sed的人都清楚它们有多糟糕。

        我记得Perl传道者曾吹嘘“关联数组”是“上帝赐予人类的礼物”,其他语言无法企及,仅仅是因为他们不了解其他语言。他们甚至没有意识到,由于Perl完全缺乏合理的引用语义,其关联数组实际上要局限得多。

    • 就连C++开发者也似乎更倾向于Python,因为其对象模型与Python相似。

    • > 我当时接触过的所有使用Perl的人都认为它不会消失

      而他们错了。Perl早已消失。

      • 不正确。我确信Perl是世界上安装最广泛的语言之一,因为它仍然是各种Unix系统中的系统组件。(也许甚至包括macOS?)

  9. Perl是我学习的第一门编程语言,因为在2000年,我当地的Books-a-Million书店将O’Reilly的Perl系列书籍大幅折扣出售($5.99至$9.99,对一名大学新生来说是笔划算的买卖),于是我就学习了Perl。

    O’Reilly的Perl书籍在写作风格上有一种调皮捣蛋的特点,这种特点也体现在语言本身中。它倡导在处理简单任务时展现出一种看似简单的风格,比如从文件中读取数据或处理用户输入,而像C++这样的语言则需要更多繁琐的操作。同样,当我用它为我工作的公司创建一个合规性测试生成器时,我只用了几天时间就写出了一个程序,可以将他们的源问题和答案转换为一个完整的网站,供人们用于进行监管合规性考试和认证。

    时至今日,我尚未发现任何其他语言能像 Perl 那样轻松地处理文本,而考虑到我们的工作中有大量文本和字符串处理任务,我仍然对其他语言未能像 Perl 那样简化这一过程感到有些惊讶。

  10. 我们的实验使用了一些用Perl编写的网络服务(DocDB)。与Python相比,它们的优势在于能够在多年未做任何修改的情况下持续运行,即使经历了多次系统更新。而用Python编写的内容则会迅速老化(回想起来,使用MoinMoin作为维基系统真是个糟糕的主意……)

  11. > 但或许Perl的启示是永恒的。它要求我们在编程语言及其设计上少些固执,多些人性化。唯有如此,我们或许才能弥合人与机器之间的鸿沟。

    我不确定作者认为这如何实现,但作为90年代开始编程的人,我认为使用Perl时必须努力理解语言的独特之处,而语言本身并未试图向程序员伸出援手以简化操作。而其他编程语言则致力于实现直观性,通过更清晰的语法、更逻辑化的命名以及框架来掩盖复杂性,在我看来,这才是更有效的桥梁。

  12. > 如果让我选择一种与 Perl 最为不同的语言,那可能是 Lisp。

    我最喜欢的两种语言是 Perl 和 Lisp——我大部分非工作相关的编程都集中在这两种语言上。

    • 既然 Matz 认为 Perl 和 Lisp 都是影响因素,你对 Ruby 的看法如何?如果 homoiconicity 是你关心的问题,它可能令人失望,但它同时拥有许多非常功能性的方面。

      • “Ruby是Lisp和Smalltalk的爱情结晶,由Perl这位古怪的保姆抚养长大”——Josh Susser

    • 确实,Perl拥有真正的lambda表达式和完整的闭包,且这一特性已存在多年。它没有全局解释器锁(GIL)。它支持多进程编程、事件驱动编程和多线程编程。它还支持可选对象。代码可以,但不必,以前缀形式并用括号包围来编写。对于来自某种 Lisp 的人来说,这感觉非常自然。

      不幸的是,它不支持自动尾调用消除,但这是工具限制而非语言限制。

  13. Perl 程序员的三大美德是急躁、自大与懒惰。

    列表中没有谦逊。

  14. 当万维网开始流行时,我还是个十几岁的少年,我父亲给我买了一本《骆驼书》。我用 Perl 编写了所有东西……一个论坛、一个我正在玩的 MUD 游戏的统计网站,基本上任何我能想到的可以放在 cgi-bin 目录里的东西。

    当然,我的代码都是垃圾,但那是一段无比有趣的经历,也是一次极具价值的学习体验。

    我怀念那些日子,但这可能与编程语言的关系不大,更多是因为那段无忧无虑的时光。 🙂

  15. 这有点讽刺,因为Perl程序员的三大“美德”之一就是傲慢,哈哈。

    (关于没人用 Perl 编程:我仍然专业地使用它,我可能永远无法理解它为什么会招致如此多的憎恨)

    • 我也写 Perl,我喜欢它。我会在正则表达式旁边添加注释,但说实话,我认为我的代码是可读且可维护的,因为我一年后再看时仍然能理解一切。

  16. 我认为 Perl 大约 20 年前就被称为“互联网的胶带”。

    你试过处理 20 年前的胶带吗?

    • 它也被称为瑞士军刀链锯。我甚至有一件这样的 T 恤。

      • 哦,我明白。它确实名副其实:就像所有维氏产品一样,它并不是适合所有它声称能做好事情的工具,更不用说它做不好的事情了。

    • 我见过朱利安拿到用胶带修补过的作品时的情景。他可不高兴。

      • 我不明白。

        • 朱利安·鲍姆加特纳是一位专业的艺术品修复师,拥有一个相当受欢迎的YouTube频道。胶带时不时地出现在他负责修复的作品中,而这总是件糟糕的事。

          事实上,在最新的一段视频(一个鼓)中,他称胶带

          > 是一种可怕的材料,因为当它新鲜时,胶水非常粘稠,难以去除,而当它变老时,胶水会变干,变得……难以去除

          他必须在同一个鼓上处理这两种情况。

    • 你不能用胶带修补破裂的杯子。 😉

      >中途,乔恩·奥尔万走了进来,站在那里听了一会儿,然后他非常平静地走到角落里的咖啡服务台,当时房间里大约有20个人,他拿起一个咖啡杯,把它扔向另一面墙,然后他继续把咖啡杯扔向另一面墙,他说 “除非我们能想出一些能激发社区热情的东西,否则我们完蛋了,因为大家都觉得无聊,开始去做其他事情了。”

      https://en.wikibooks.org/wiki/Raku_Programming/Perl_History#

      间歇:2000年乔恩·奥尔万特扔杯事件

      到2000年,显然Perl需要注入新的活力:

      “[P5P / Perl 会议]最初是由 Chip Salzenberg、Jarkko Hietaniemi、Elaine Ashton、Tim Bunce、Sarathy、Nick Ing-Simmons、Larry Wall、Nat Torkington、brian d foy 和 Adam Turoff 等人召集的,目的是起草一份类似宪章的文件,因为社区似乎正在分裂。Jon迟到了,发现我们在讨论社区问题,于是开始发泄对Perl自身停滞不前、甚至可能走向衰亡的不满,并主张我们应讨论如何复兴Perl。据我后来所知,‘杯子事件’是预先策划的戏剧性表演。因此,此事已成定局,但这场发泄情绪的闹剧正是其公开化的表现。”[1]

      https://www.nntp.perl.org/group/perl.packrats/2002/07/msg3.h

      Andrew.Savige@ir.com [Andrew.Savige@ir.com] 说道:

        *>我对这起事件很感兴趣。
        *>这是否真的是当前 Perl 6 开发的主要催化剂?
      

      嗯……称其为催化剂可能有些夸张。这次会议最初是 Chip Salzenberg、Jarkko Hietaniemi、我、Tim Bunce、Sarathy、Nick Ing-Simmons、Larry Wall、Nat Torkington、brian d foy 和 Adam Turoff 的聚会,旨在起草一份类似宪章的文件,因为社区似乎正在分裂。Jon迟到了,发现我们在讨论社区问题,于是开始扔东西来表达他对Perl本身停滞不前、甚至可能消亡的不满,并认为我们应该讨论如何复兴Perl。据我后来所知,杯子事件是预先策划的戏剧。因此,事情已经成定局,但这场闹剧只是它的公开表现。

        *>有多少杯子被打破了?
      

      只有一个。扔了五个,但它们很结实 🙂

        *>它们是咖啡杯还是咖啡杯?
      

      咖啡杯。标准酒店用品。

        *>它们是什么颜色?
      

      白色。

        *>有人保留了一些破碎的杯子,以便以后在博物馆展示吗?
      

      没有 🙂

        *>有人拍摄了事故现场或破碎的杯子吗?
      

      没有 🙂 幸好没有,否则我可不希望有张我躲在桌子底下的照片。

      https://web.archive.org/web/20110716115800/http://www.spider… 可能是你能找到的最接近这张照片的了 🙂

      e.

      • 人类事务中确实存在一股潮流。到2000年,这股潮流已将Perl推至孟菲斯,在那里它成为我认为自己开始进行“真正编程”的第一门语言,不久后便成为开启我工程职业生涯前20年的跳板,而这20年很可能将体现蒂姆·莱里(Tim Leary)曾声称认可的角色。(上一次与计算机进行真正对话还是公众日常用语的一部分时,他当然也在其中!一如既往地对一切都持错误观点,但有时却以一种挑衅的方式。)

        我并不后悔停止使用 Perl,无论杯子是否破碎;回想起与它共度的时光,让我不禁联想到我认为维尔特对早期接触 BASIC 的危险性的评论,以及 2000 年代末和之后的“The Rails' Progress”,我认为这是相应的闹剧。

    • Perl后来被称为“可执行行噪音”。

  17. 提到Perl总会让我想起那次我在一家Ruby公司提交Perl代码的PR。那是一段美丽、便携的小代码,他们让我把它带出去,从背后开枪打死它。公平地说,但我永远无法释怀,哈哈。我甚至不再为个人工作编写 Perl 脚本,我使用 Python(只是因为 uv 让它不那么糟糕),但这并不是重点!

  18. 当我想到 Perl 时,首先想到的绝不是谦逊,这并不是因为 Perl 僧侣不谦逊,他们确实很谦逊,甚至启发了 Ruby 开发者,因为 Ruby 开发者很谦逊,我想是因为 Perl 开发者很谦逊吧 😀 但就像我之前在其他地方说的那样,Perl 就像九十年代的音乐,它就是最好的,所以在我的眼中,Perl 程序员是(Unix)老手,是最有经验的程序员。所以别以为他们会谦逊,因为他们的专业水平足以让他们有些自负。:D 总之,这就是我对编程语言和 Linux 发行版的类比。Slackware 是为 Lisp 创建的,其 KISS 原则后来在 Clojure 中得到体现。早期 Debian 发布的 Perl 版本与《学习 Perl》一书中的版本相同。两者都非常重视可重复性和测试。而 Red Hat 和 IBM 等企业的核心业务是 Java,Red Hat 的 CEO 甚至参与了 Unity(一个 Mono 的分支)的开发。因此,Perl 虽然源自 Unix,但它塑造了 Linux,进而影响了整个开源世界。它就像一位知晓所有答案的长者,只是没人去问。编辑:啊,是的,Larry 关于 Tim Toady 的说法确实没错,无论是 Perl、Python 还是其他语言都适用。:D

  19. 我年纪不够大到学会 Perl,但也不够年轻到对 Perl 和其问题一无所知。

    但如果将文章或至少标题中的“Perl”替换为“CUDA”,会更合适。你无法在使用它时保持傲慢,因为即使是自我中心的人也会承受足够的痛苦而不愿改变。如果Perl让你觉得它是人类创造的,那么“CUDA”肯定会让人感觉像是直接来自地狱。

    注:我明白这篇文章更多是关于讨论Perl,提醒人们它曾经存在并曾是一门著名的编程语言。但我无法抗拒标题的诱惑。

    • 有趣的是,我曾共事过的最固执己见、自以为是的工程师之一,对CUDA简直到了狂热的程度。

      他不停地谈论CUDA,认为其他一切都糟糕透顶,抱怨没人听他的,说那是因为他们无法接受真相,还说只要让他动手,他就能解决所有人的问题,如此循环往复。他在我公司没待多久就离开了。

      也许他把对CUDA的痛苦转嫁到了别人身上。

  20. 大约在2015年左右,我环顾四周,发现年轻一代(<35岁)似乎都懂Python,而中年及以上(>45岁)的人似乎都懂Perl。我决定,未来的工作,只要有选择,我都会用Python。有几次我犹豫了,但那些机会都消失了。

    在过渡初期,我不得不查阅Python的惯用表达方式,来替代我在Perl中熟练掌握的代码。过去几年,当在Perl中进行一次性开发时,我会省略分号、省略大括号,并依赖显著的缩进。我还能写Perl吗?是的,而且写得不错,但不像2018年前那样流畅。

  21. 那些我喜欢存在且确实存在的开发者,正是最让我烦恼的群体。他们不知道自己不知道什么,现在却自诩为高级开发者,而其中大多数人连SQL是什么意思都不知道。其他人则挺胸抬头说“我是程序员”,真是该有点谦逊啊。疏通马桶并不代表我是水管工

  22. 不,是因为我们拿的薪水太高了。

    • 一旦钱开始流入,科技行业就吸引了那些只为赚钱而做的人,而不是出于对科技的热爱。

      大型科技公司某种程度上取代了华尔街成为某些人的主要职业选择,自然也吸引了“华尔街兄弟”类型的人进入科技行业,他们现在被称为“科技兄弟”

      • 或者,有人可能会认为,资金的涌入和硬件能力的不断提升,使得更合理、更人性化的语言成为可能。这种人性化体现在设计上,即更容易学习,更符合人类的思维模式,同时也更考虑人类的认知偏差。这是老语言和较低抽象层次无法做到的,因为验证或防范人类错误的成本太高。

  23. 我喜欢90年代Perl社区的机智和魅力,当时我正沉迷于Perl。

    我的 Perl 学习路径与这里许多人相似。我当时在制作游戏并学习 C 语言,后来从朋友那里了解到 Linux。随后我听说 Perl 并开始用它来自动化制作网站……那是在有人开始称它们为“网络日志”(web logs)并后来演变为“博客”(blogs)等术语之前的黄金时代。

    在 Perl 中处理文本和操作文件比在 C 中要容易得多,我因此成了它的忠实粉丝。

    社区氛围非常棒。书籍也非常出色。

    我觉得 Perl 体现了编程/科技领域中那种“嬉皮士-社会主义集市”风格的黄金时刻。

  24. 我无法阅读这篇文章,因为它有付费墙,但至少根据标题,我来发表一下我的看法:现在几乎没有人再用Perl编程了,因为在从Perl 5过渡到Perl 6(即Raku)的过程中,这门语言失去了大量市场份额。而且无论如何,Perl一直都是一门在很多方面都相当独特且个性鲜明的语言。像 Ruby(它从 Perl、Lisp 和 Smalltalk 继承了部分特性)、PHP(也从 Perl 借鉴了一些元素,或许更浅显)和 Python 这样的语言抢走了它的风头。

    这是我职业生涯中第一个使用的编程语言,我一直觉得它很有趣,但如果我想要被现实打脸,我会选择 Haskell(听起来很多 Perl 社区的人也是这样……)。

    EDIT:我读了这篇文章,感谢welpo提供的存档链接。是的,这篇文章有点怀旧,所以我认为我之前的评论仍然适用。我仍然喜欢Perl,我心中永远有一席之地留给它。我特别欣赏Larry Wall在语言学方面对事物进行深入思考的努力,即使我并不认为这是当今工程团队使用语言的最佳方法。

    无论如何,我希望它能继续存在。它确实独一无二。

    • 我同意这是Raku和Ruby的结合。就我而言,Ruby取代了Perl 5。它填补了相同的空白,同时避免了Perl中许多绝对疯狂的部分(没有贬低之意;Perl是在一个截然不同的时代和环境下设计的)。如果你了解 Ruby,那么学习 Perl 几乎没有必要。我对这门语言有着美好的回忆,它是我的第一门专业编程语言,但再也不会使用了。

      Raku 长期处于不确定状态,这使得它在与 Ruby 的竞争中失去了市场份额。

      • > 如果你了解 Ruby,那么学习 Perl 几乎没有必要。

        我从未刻意思考过这个问题,但自上次认真使用 Perl 以来,我似乎已将此观点内化。过去十年我所任职的几乎每家工程团队都将 Ruby 纳入技术栈,用于脚本编写或 lambda 表达式,而当我需要编写脚本时,也会优先选择 Ruby。我也在几个组织中做过 Rails 工作,即使不考虑 Perl,它在自己的领域中也几乎没有平行替代品。

        虽然我怀疑对于大多数人来说,如果只是谈论脚本编写或快速拼凑一些东西……或者任何事情(我讨厌它,但它就是这样,哈哈),Python 就是他们的选择。

      • > 如果你会 Ruby,几乎没有理由去学习 Perl

        在我还使用 Perl 的时代(大约 10 年前),Ruby 在许多任务上明显更慢。Ruby 可能是流行脚本语言中速度最慢的。

    • 我曾广泛使用 Perl 进行小型网络(约 25 台服务器)的系统管理和本地/个人工具开发,但从未在集群/多节点部署的生产环境中使用过。它提供了过多的表达自由,使得团队协作变得困难。

      我大约在2000年停止使用Perl,原因并非特别明确,只是因为Python更容易被团队采用,且常见模块已维护得足够完善,使得CPAN不再具备竞争优势。此外,当时Guido住在弗吉尼亚州雷斯顿市,距离我仅几分钟车程,这也起了一定作用。

      不过,我至今仍以Perl正则表达式的方式思考问题。 😉

      • > 不过,我至今仍以 Perl 正则表达式的方式思考。;)

        没错,如果说 Perl 有什么东西能比语言本身存活更久,那就是 PCRE。我无法感谢 Perl 语言给我带来的正则表达式编写能力。

      • 同意,Perl 让我接触了正则表达式和哈希。时至今日,每当我处理数据时,我倾向于首先以正则表达式的方式思考,而非复杂的字符串操作。

    • 和许多付费墙一样,关闭JS后它就会消失。

  25. 我使用Perl,它仍然快速且非常直观,适合编写小型代码(但不适合在过了一周后阅读它)

  26. 我每年会写一两次新的Perl/Gtk应用程序。我几乎每天都用它来自动化一些基本任务。我敢打赌,很多人选择用Perl来做个人项目。只是它不太引人注目。

    但也不是_那么多_。这就是为什么Perl还是Perl。流行度带来变化,这意味着旧代码不再工作。

    2000年的Perl代码至今仍能在Perl解释器+库中运行。而今天编写的Perl代码也能在2000年的Perl解释器+库中运行。这种令人惊叹的稳定性和可靠性正是其伟大之处。你写好代码后,20年后再使用,无论在何处运行,一切都能正常工作。

    这就是我选择Perl的原因。

    • 我今天编写的 Perl 代码极不可能在 2000 年的 Perl 版本上运行,除非是简单的单行代码。

  27. 嗯。而 Perl 并非当今最流行的语言之一。与 Python 及其

      应该只有一种——而且最好是唯一一种——显而易见的方法来实现它。
    

    这似乎并非巧合

    • 当今的Python世界中几乎没有东西遵循这一原则。

      每年都会出现新的包管理器。语言特性在每次重大版本发布时都会被引入。

      • 但有500个代码检查工具可以帮助你进行符合Python惯例的编码。心怀不轨者自取其辱……

    • 是的,我认为“TIMTOWTDI”(通往同一目标的多种路径)最终成为了一种负面影响。当然,随着经验的积累和对惯用法(Perl 非常注重惯用法)的掌握,情况会好转,但这对初学者来说确实增加了认知负担。

      虽然 Perl 仍然广泛存在,但我会有点惊讶如果任何新项目会使用它,至少在它没有强大存在感的地方。

    • 仍然有一些 Perl 程序员存在,尽管它远不如几十年前那样流行。

    • 我的意思是,通常有一种显而易见的方法来做某事,然后还有许多不那么显而易见的方法,最后,如果你主要使用Pandas或NumPy进行编程,那么Python更多地是一种实现细节。

      我同意引文的意图,但遗憾的是,事情并没有按照那样发展。

    • Perl 不是首字母缩写词。

  28. Perl 是一种混乱、令人抓狂的编程语言

    仅仅是因为人们一直编写糟糕的代码并以 Perl 为借口。Perl 就像 C 语言,你的代码的可读性和可维护性取决于你如何编写。这就像那句老话所说,不要怪工具。只要停止编写垃圾代码。

  29. 现在的孩子们不再把 Malbolge 作为他们的第一门语言,这真的显而易见。

    我喜欢 Basic,然后是 VisualBasic,然后是 C,然后是 Perl……在 Perl 之后,我从未觉得学习新语言有多难。在花了近一年的时间编写一些 CGI 脚本(我记得是 Gossamer Threads?)后,我突然意识到,我并不理解自己花大量时间编辑的那段代码的上下文。那是一个多页的正则表达式。我(至今仍)对语言的实现或解析方式知之甚少,而我们仅凭对底层细节的浅薄理解就能编写代码,这一点让我感到非常有趣。我对Lisp也处于类似阶段,偶尔能窥见表象下的奥秘,但如今已通过数十年的深入研究和探索其他语言积累了丰富经验。有时我认为回到 Perl 可能会很有趣,但当我阅读现代 Perl 代码时,它似乎与 25 年前的代码几乎毫无相似之处。

  30. Perl 的符号很糟糕;Perl 的魔法变量很糟糕,Perl 缺乏合理的对象和参数传递也很糟糕。(Moose 是一个改进,但速度很慢,如果我记得没错的话。)它是一种建立在其他权宜之计之上的权宜之计语言。

    我猜它之所以流行,是因为它存在,而且没有更好的选择(没有人会在没有压力下用 awk 编程)。

    我们不需要设计糟糕的工具来保持谦逊。所有糟糕的程序员(现在还有大语言模型(LLMs) 喷出的垃圾)已经给我们带来了足够的认知负担,无需再添加其他无意义的东西。

    我承认,编写 Perl 会让你觉得自己“聪明”——“咦,这是个有趣的快捷方式,我以前不知道!编写 $<>^^ 会给我周四蓝月亮上最后使用的文件名!”但……嗯。

    • > 我承认,编写 Perl 确实让人觉得“聪明”——“哇,这真是个有趣的快捷方式,我之前不知道!输入 $<>^^ 就能得到周四蓝月亮时最后使用的文件名!”但……嗯。

      我写 Perl,我非常讨厌这种心态。非常讨厌。有些人会兴奋地觉得自己像是白袍议会的魔法大师,因为他们能把所有符号排列好让它们跳舞,从而感到自己比别人高明一点。但维护一个程序时,每次修改都需要先解决三个谜题,做出修改,再用另一个谜题包裹起来留给下一个人,这根本没什么高明可言。

      我明白那种当魔法师的感觉,我过去也曾露出那种自满的表情。但现在我已经四十多岁了,我在一个神奇的代码库中来回跳跃进行调试,我不禁觉得,如果它能少一点神奇,我早就修好了,早就结束了。

  31. 我怀念Perl。我在1998年上学时遇到了它,并一见钟情。我专业使用它的时间远超合理范围,考虑到当时的编程规范和程序员的可用性。骆驼书塑造了我对软件应有的形态的初始观点,我肯定会永远在内心深处是个Perl程序员。

    我在2020年放弃了它,认为Python已经胜出。那是一个悲伤的日子——用Python编程感觉就像缺了三根手指打字。当我试图使用一个惯用语时,不仅找不到它,还被告知“幻肢综合征”对每个人都有好处,包括我。

    我从未觉得资深 Perl 程序员的代码难以阅读。我认为糟糕的程序员无论使用何种语言,都会写出难以维护的代码。我理解他人代码时最痛苦的经历,来自一位才华横溢、过于聪明但缺乏经验的 Python 程序员。我必须承认,这种混乱的程度需要一个天才才能达到,而 Perl 则让在三十码范围内让所有人踩到雷变得相当容易。尽管如此,我一直认为 Perl 的混乱是神话,是误用、滥用和缺乏经验的结果。写得好的 Perl 代码能让人一目了然,而在视觉上更干净的语言中,所有形状都有相同的轮廓。

    但事实是,当我放弃 Perl 时,我已经开始寻找替代品。这门语言大胆、美丽且充满个性,但随着时间的推移,其中一些观点被证明是错误的。世界在前进,而 Perl 没有,我发现自己想要做一些 Perl 无法做到或做不好的事情,比如对象、类型、工具、函数和异常。一些语言,如PHP和JavaScript,超越了它们 humble 的起源,并添加了现代世界中严格且日益必要的机制。Perl 没有。

    因此,我离开的原因有两个主要因素:语言没有成长,人们不愿阅读我的代码。

    我仍在寻找替代方案。目前的主要候选者是Go和Ruby,我对这两种语言都非常喜欢。我也在尝试Haskell和Lisp,希望能找回一些失去的东西。出于职业义务,我与Python和JavaScript达成了一个不安定的停火协议。虽然我们能合作,但坦白说,双方都不太满意这种状态。

    Perl是一件美丽的事物,我像欣赏艺术和诗歌一样欣赏它。我很高兴能在它繁荣的年代参与其中。但我认为世界已经超越了它。即使不考虑那些拼凑的功能,它也有更根本的问题。标准化与表达之间的拉锯战,就像社会与个人之间的拉锯战。双方都不应完全获胜,但Perl更倾向于表达,而这在今天看来并不明智。当时我们并不知晓这一点。那种感觉令人陶醉。但在随后的几十年里,我们所有人——包括我在内——都认为这种平衡……嗯,我们并不确切知道它在哪里,但我们知道它涉及的个人自由比那要少。这门语言做出了许多错误的赌注,但这是最大的一个。

    顺便说一句,我认为 Lisp 也陷入了同样的困境。它如此无拘无束且富有表现力,以至于等你写完软件时,你基本上已经为它发明了一种专属语言。在项目狭窄的范围内,语言与领域完美契合。但如果你需要雇佣帮助,那就糟糕了。招聘广告中要求掌握Emacs Lisp或AutoCAD Lisp的人员,就说明了问题。你可以发明世界上最美丽的语言,但只有三个人会说它,这无疑是一个强大的反对理由。

    Perl 曾经是一件美丽的事物。我怀念它。我尽可能地寻找它的后代。我写笑话、引用和悼词,将从 Perl 偷来的实用函数塞进那些不属于它们的语言中,那些从未接触过 Unix 遗产的地方。Perl 足够谦逊,它给你空间让你按自己的方式做事,而不是按它的方式,它允许你打破所有规则,并要求你用智慧、善良和礼貌来使用这种自由。这种大胆的信仰和慷慨在我心中激起了强烈的爱。我从未在其他地方找到过它。我怀疑我不会找到,因为尽管它很美好,但它已被认为是不明智的。编程是一项社会性活动,虽然像 GLSL 这样的专业语言可以在一个小众领域蓬勃发展,但一种只有少数人使用的粘合语言根本不是粘合语言——它只是另一个需要被粘合的神秘系统。不,Python 赢了。也许它甚至配得上胜利。

    所以对我来说,Perl 已死……但愿 Perl 永存。

  32. 发现 Perl 让我感觉自己像个神。

  33. > 如果我必须选择一种与 Perl 最为不同的语言,那可能是 Lisp。

    Rust

    • 它们同样依赖大量标点符号,都采用C语言衍生语法,且均为命令式语言,因此我不同意这种说法。

    • 但Perl拥有类似Lisp的列表嵌套函数。虽然它们看起来不同,但共享这一重要特性。

      我认为Perl是shell与Lisp结合的产物。

    • 他说的是最远的。那可能是Lisp或Haskell,或是类似的语言。

  34. 付费墙

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

链接收藏


京ICP备12002735号