【问题标题】:Is there a way to perform compile time type-check in Ruby?有没有办法在 Ruby 中执行编译时类型检查?
【发布时间】:2014-02-08 07:46:43
【问题描述】:

我知道 Ruby 是动态且强类型的,但据我所知,当前的语法不允许在编译时检查参数的类型,因为每个参数都没有明确的类型表示法(或协定)。

如果我想执行编译时类型检查,我有哪些(实际上成熟的)选项?

更新

我的意思是 type-check 类似于典型的静态类型语言。比如C。 例如,C 函数表示每个参数的类型,编译器检查传入的参数是否正确。

void func1(struct AAA aaa)
{
    struct BBB bbb;
    func1(bbb);  // Wrong type. Compile time error.
}

作为另一个例子,Objective-C 通过放置明确的类型信息来做到这一点。

- (id)method1:(AAA*)aaa
{
    BBB* bbb = [[AAA alloc] init];  // Though we actually use correctly typed object...
    [self method1:bbb];             // Compile time warning or error due to type contract mismatch.
}

我想要这样的东西。

更新 2

另外,我的意思是 compile-time = 在运行脚本之前。我没有更好的词来形容它……

【问题讨论】:

  • 请举例...您要检查什么?
  • @ArupRakshit 我更新了问题以添加示例。
  • 你有编译器吗?
  • @Eonil 所以你想要 Ruby 中的静态类型?
  • 简单回答:不。而且你做错了。你完全错过了鸭子打字的意义。

标签: ruby compile-time typechecking


【解决方案1】:

有一个项目用于为 Ruby(的子集)开发类型系统、类型推断器、类型检查器和类型注释语法,称为 Diamondback Ruby。 4年前被废弃了,可以找its source on GitHub

但是,基本上,该语言将不再是 Ruby。如果静态类型对您来说如此重要,您可能应该只使用静态类型语言,例如 Haskell、Scala、ML、Agda、Coq、ATS 等。毕竟,这就是它们的用途。

【讨论】:

【解决方案2】:

RDL 是一个用于对 Ruby/Rails 程序进行静态类型检查的库。它包含标准库和(我认为)Rails 的类型注释。它允许您向方法/变量/等添加类型。像这样:

文件.rb:

require 'rdl'

type '(Fixnum) -> Fixnum', typecheck: :now
def id(x)
  "forty-two"
end

然后运行file.rb会进行静态类型检查:

$ ruby file.rb
.../lib/rdl/typecheck.rb:32:in `error':  (RDL::Typecheck::StaticTypeError)
.../file.rb:5:5: error: got type `String' where return type `Fixnum' expected
.../file.rb:5:     "forty-two"
.../file.rb:5:     ^~~~~~~~~~~

它似乎有很好的记录!

【讨论】:

    【解决方案3】:

    虽然您无法在静态时间意义上对此进行检查,但您可以在方法中使用条件,以便仅在检查对象后运行。
    这里#is_a?#kind_of? 派上用场了……

    def method(variable)
        if variable.is_a? String
            ...
        else
            ...
        end
    end
    

    您可以选择返回指定的错误值或引发异常。希望这与您正在寻找的内容接近。

    【讨论】:

      【解决方案4】:

      您要求进行“编译时”类型检查,但在 Ruby 中,没有“编译”阶段。几乎不可能对 Ruby 代码进行静态分析,因为任何方法,甚至是内置类中的方法,都可以在运行时重新定义。类也可以在运行时动态创建和实例化。当程序启动时,你将如何对一个甚至不存在的类进行类型检查?

      当然,您的真正目标不仅仅是“对代码进行类型检查”。您的目标是“编写有效的代码”,对吗?类型检查只是一种工具,可以帮助您“编写有效的代码”。然而,虽然类型检查很有帮助,但它也有其局限性。它可以捕获一些简单的错误,但不能捕获大多数错误,也不能捕获最困难的错误。

      当您选择使用 Ruby 时,您就放弃了类型检查的好处。然而,与您习惯使用的其他语言相比,Ruby 可能 允许您使用更多 代码来完成工作。使用 less 代码编写程序意味着通常需要修复的错误更少。如果你熟练地使用 Ruby,我相信这种权衡是值得的。

      虽然您无法在 Ruby 中对代码进行类型检查,但使用检查方法参数的断言具有很大的价值。在某些情况下,这些断言可能会检查参数的类型。更频繁地,他们会检查参数的其他属性。然后你需要一些测试来练习代码。您会发现,通过相对较少的测试,您将捕获比您的 C/C++ 编译器更多的错误。

      【讨论】:

      • 我的目标不仅仅是编写有效的代码。我的目标是尽可能正确、轻松、快速地完成工作。根据我的经验,在没有类型检查的情况下,总是需要更多的代码来满足这三个条件,因为我必须手动编写类型检查自动执行的所有检查。那是因为我是一个超级容易出错的人,所以没有自动检查工具,为我编写正确的代码需要很长时间。
      • 根据您使用它的方式,Ruby 可以帮助您“正确地完成工作”,比您使用的其他语言更容易、更快速。但是你不能盲目地应用你已经知道的每一种技术。 Ruby 与您学过的其他语言(至少是您个人资料中列出的那些)非常不同,为了有效地使用它,您必须稍微改变一下您的思维方式。有些事情一开始可能没有意义,但随着您对这种新语言的深入了解,它们就会变得有意义。
      【解决方案5】:

      您似乎想要静态类型。由于语言的动态特性,在 Ruby 中没有有效的方法来执行此操作。

      我能想到的一种天真的方法是像这样制定“合同”:

      def up(name)
        # name(string)
      
        name.upcase
      end
      

      所以每个方法的第一行将是一个注释,声明每个参数必须具有什么类型。

      然后实现一个工具,该工具将静态扫描和分析源并通过扫描上述方法的调用站点来捕获此类错误,并检查传递的参数的类型尽可能

      例如,这很容易检查:

      x = "George"
      up(x)
      

      但是你将如何检查这个:

      x = rand(2).zero? "George" : 5
      up(x)
      

      换句话说,大多数时候类型是不可能在运行前推断出来的。

      但是,如果您不关心静态发生的“类型检查”,您也可以这样做:

      def up(name)
        raise "TypeError etc." unless name.is_a? String
        # ...
      end
      

      无论如何,我认为您不会从上述内容中受益。我建议改用鸭子打字。

      【讨论】:

      • 第二个例子的类型可以建模为联合类型 String | Integer.
      【解决方案6】:

      您可能对“可插入类型系统”的想法感兴趣。这意味着将静态类型系统添加到动态语言中,但程序员决定应该键入什么,什么不键入。类型检查器与核心语言无关,通常作为库实现。它既可以进行静态检查,也可以在运行时以特殊的“检查”模式检查类型,这种模式应该在开发和执行测试期间使用。

      我发现的 Ruby 类型检查器称为 Rtc(Ruby 类型检查器)。 Githubacademic paper。其动机是明确对函数或方法的参数类型的要求,将要求从测试中移出到类型注释中,并将类型注释变成“可执行文档”。 Source.

      【讨论】:

        猜你喜欢
        • 2020-05-25
        • 1970-01-01
        • 2021-11-07
        • 2021-06-12
        • 1970-01-01
        • 2020-04-08
        • 1970-01-01
        • 2011-04-26
        • 2022-10-12
        相关资源
        最近更新 更多