【问题标题】:Is Automatic Refactoring Possible in Dynamic Languages?动态语言中是否可以进行自动重构?
【发布时间】:2011-01-20 00:41:01
【问题描述】:

也许我受到动态语言(Netbeans 上的 Ruby 和 Eclipse 上的 Groovy)经验的限制,但在我看来,动态语言的本质使得重构(重命名方法、类、上推、拉取)变得不可能-down 等)。

是否可以使用任何动态语言(使用任何 IDE/工具)自动重构?我对 Ruby、Python 和 Groovy 以及重构与 100% 自动重构的比较特别感兴趣在所有 Java IDE 中都可用。

【问题讨论】:

    标签: refactoring dynamic-languages


    【解决方案1】:

    鉴于自动重构是在动态语言 (Smalltalk) 中发明的,我不得不说“是”。

    特别是,John Brant、Don Roberts 和 Ralph Johnson 开发了 Refactoring Browser,它是 Squeak 等的核心工具之一。

    我的 Google-fu 今天很弱,但你可以尝试找到这篇论文:Don Roberts、John Brant 和 Ralph Johnson,A Refactoring Tool for Smalltalk,“对象系统的理论与实践”,(3) 4, 1997 年。

    【讨论】:

    • 虽然这个历史记录很时髦(请原谅双关语),但我并不想弄清楚它是否可能。即使在 Ruby 中,我们也有“自动重构”,但实际上它不起作用。在 Netbeans 中甚至有一个警告,但现实是相当惨淡的。另外,我不知道您是否在 Smalltalk 中声明所有类型,这将有助于重构。在 Ruby 中你不会,这是让它变得如此困难的原因之一。
    • 对不起,我不是只想提供历史记录。我的意思是建议重构浏览器是许多 Smalltalk IDE 中的标准工具
    【解决方案2】:

    Smalltalk 不声明任何类型。自 1995 年以来,Refactoring Browser 已经成功地在商业代码中执行了正确的重构,并且几乎包含在所有当前的 Smalltalk IDE 中。 - 唐·罗伯茨

    【讨论】:

    • 谢谢 Don,现在我只需要在 Smalltalk 找到一份工作。如何在不声明类型的情况下进行重构(请原谅我的无知)?
    【解决方案3】:

    自动重构是在高度动态的语言 Smalltalk 中发明的。 从那以后,它就像一种魅力。

    您可以试用免费的 Smalltalk 版本(例如 http://pharo-project.org

    在动态语言中,您还可以自己编写重构脚本或查询 系统。获取测试类数量的简单示例:

    TestCase allSubclasses 大小

    【讨论】:

      【解决方案4】:

      同上关于重构浏览器的观点......它在 Smalltalk 中非常有效。但是,我想如果没有类型信息,某些类型的重构是不可能的(无论是通过语言中的显式类型注释还是通过动态语言中的某种形式的类型推断来获得都无关紧要)。一个例子:在 Smalltalk 中重命名一个方法时,它会重命名该方法的所有实现者和发送者,这通常很好,但有时是不可取的。如果您有关于变量的类型信息,您可以将重命名的范围仅限于当前类层次结构中的实现者以及当消息被发送到声明为该层次结构中的类型的变量时的所有发送者(但是,我可以想象场景即使使用类型声明,也会崩溃并产生不良结果)。

      【讨论】:

      • 谢谢。这是什么意思“它将重命名该方法的所有实现者和发送者”?方法是全局范围的(或类似的?)?
      • 另外,今天是 Smalltalk 日还是什么?我永远不会明白为什么这个问题会走上 smalltalk 路线。您在某处看到链接吗?它更多地是关于 Python、Ruby 和 Groovy,但 ST 作为一个案例显然是有效的。
      • @yar:当然,方法是全局范围的。在 Python 和 Ruby 中必须是相同的,但是如果一个方法接受一个参数并向参数上的方法发送消息/调用该方法,它将适用于实现该方法的所有类,因此重命名,例如,一个调用站点将意味着重命名所有调用站点和实现。只有您知道在运行程序时哪些重命名子集仍然有效。
      • @quamrana 也许我不知道我们在说什么。在 Ruby 中,一个类上的方法在那个类上 :)... 但是它们可以从其他地方混入。
      • @yar:当然,任何类上的方法都有名称,并且在动态语言中调用方法的任何地方都不知道调用该方法的对象的类。它只知道方法的名称。因此,哪些类有一个给定名称的方法,它们的实现并不重要,只是名称的拼写。
      【解决方案5】:

      我也想知道同样的事情。我不是编译器/解释器作家,但我认为答案是不可能让它完美。但是,在大多数情况下,您可以正确判断。

      首先,我将把“动态”语言的名称更改为“解释性”语言,这是我对 Ruby、Javascript 等的看法。解释性语言倾向于利用运行时功能。

      例如,大多数脚本语言允许以下内容

      -- pseudo-code but you get the idea
      eval("echo(a)");
      

      我只是“跑”了一个字符串!您还必须重构该字符串。 a 会是一个变量吗?如果没有变量 a,这种语言是否允许您打印不带引号的字符 a?

      我想相信这种编码方式可能是个例外,并且您几乎在所有时间都会得到很好的重构。不幸的是,当我查看脚本语言库时,它们通常会遇到此类异常,甚至可能基于它们的架构。

      或者提高一点赌注:

      def functionThatAssumesInputWillCreateX(input)
          eval(input)
          echo(x)
      
      
      def functionWithUnknownParms( ... )
         eval(argv[1]);
      

      至少当你重构 Java 并将变量从 int 更改为 string 时,你会在所有期待 int 的地方得到错误:

      String wasInt;
      out = 3 + wasInt;
      

      对于解释型语言,您可能要到运行时才能看到这一点。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-01-14
        • 2013-04-20
        • 1970-01-01
        • 2014-04-18
        • 2010-12-12
        • 1970-01-01
        • 2019-07-04
        相关资源
        最近更新 更多