【问题标题】:Class versus instance methods in the context of global symbols全局符号上下文中的类与实例方法
【发布时间】:2017-09-07 11:21:02
【问题描述】:

我正在阅读 Dave Copeland 撰写的关于 Service Objects 的博客文章,并看到以下内容:

Ruby 中的类是全局符号,这意味着类方法是全局符号。编码为全局变量是我们不再使用 PHP 的原因。

我想进一步理解这个陈述,并有一些问题。

  • 类方法和实例方法在符号上下文中有何不同?

例如,采取以下 irb 会话:

irb(main):001:0> Symbol.all_symbols.grep /Foo/
=> []
irb(main):002:0> Symbol.all_symbols.grep /some.*method/
=> []
irb(main):003:0> class Foo
irb(main):004:1> def some_instance_method; end
irb(main):005:1> def self.some_class_method; end
irb(main):006:1> end
=> :some_class_method
irb(main):007:0> Symbol.all_symbols.grep /Foo/
=> [:Foo]
irb(main):008:0> Symbol.all_symbols.grep /some.*method/
=> [:some_instance_method, :some_class_method]
  • #some_instance_method::some_class_method 在符号上下文中有何不同?
  • 当我检查Symbol.all_symbols时我在做什么与查看“全局符号”是一样的吗?
  • 为什么会同时显示#some_instance_method::some_class_method?在阅读了上面的引用后,我预计008 的结果是:

    irb(main):008:0> Symbol.all_symbols.grep /some.*method/ => [:some_instance_method]

【问题讨论】:

    标签: ruby class oop global symbols


    【解决方案1】:

    问题 1

    :some_instance_method:some_class_method 符号仅存在于 Ruby 的符号表中。它们在符号的上下文中没有不同。 Symbol.all_symbols 结果没有声明任何关于被引用对象的内容。如果你有:

    class Aaa
      def kick_it
        logger.debug { "You kicked an Aaa object" }
      end
    end
    module Bbb
      def self.kick_it
        logger.debug { "You kicked Bbb" }
      end
    end
    

    您只会看到Symbol.all_symbols 报告的 1 个:kick_it,即使其中一个是模块级方法而另一个是实例方法。

    问题 2

    文章中使用“符号”一词可能会让人感到困惑。此处的“全局符号”可能意味着集合 Object.constants 的成员的名称,或定义的常量子树中可访问的任何其他常量。

    所以Symbol.all_symbols 在这种情况下与“全局符号”不同。但是,内存中常量树中的所有名称都是 Symbol.all_symbols 的子集,请记住,所有范围信息都在那里丢失。

    问题 3

    我认为上面的问题 1 答案也解释了为什么两个符号都显示在 Symbol.all_symbols 结果中。

    【讨论】:

      【解决方案2】:

      我发现那篇文章有几个问题:

      首先,使用“symbol”这个词可能会造成混淆。事实上,这个词确实完美地描述了作者的意思,但有些读者可能会将它与 Ruby 中的 Symbol 数据类型混淆。因此,虽然没有错误,但在 Ruby 的上下文中,单词的选择是不幸的。 “名称”可能是更好的选择。

      其次,他对类方法和实例方法做了人为的区分,但是Ruby 中没有类方法这种东西。 Ruby 只有一种方法:实例方法。我们所说的“单例方法”实际上只是单例类的常规实例方法,而我们所说的“类方法”实际上只是一个对象的单例类的常规实例方法,该对象恰好是Class的实例类。

      第三,他对类和对象做了人为的区分,但是在 Ruby 中类就是对象

      看来我们他真的反对的是常量(因为它们是全局名称)、单例(通常是哪些类)和静态。虽然所有这些都是坏的,但他应该这么说,如果他是这个意思的话。 (这也不完全是一个新发现;整个编程语言都是基于避免静态状态而设计的,例如Newspeak。)

      tl;dr 摘要:文章反对全局名称、单例和静态,但呈现和措辞都很糟糕。

      【讨论】:

      • “静态”的概念和“无状态”的概念有关系吗?因为您说他在反对“静态”,但似乎他在为“无状态”对象争论;但“静态”似乎类似于“无状态”。另外,文章中没有提到“静态”(我认为你的意思应该是?)所以我对你所说的“静态”感到困惑。
      • @mbigras Ruby(和其他一些人)所说的“类方法”也被其他语言称为静态方法。据我所知,无国籍与 Jörg 的回答无关。
      • @mbigras:无状态比没有静态更具侵略性。我的意思是,如果您根本没有状态,那么您显然也没有静态状态,但是 OP 并不是说​​您根本不应该有状态,他只是在争论状态不应该是静态的。我想一个更合适的特征是状态不应该是环境。静态(或环境)状态的问题在于它们只有一个,只有一个环境环境,只有一个静态名称,因此您不能有多个 Resque 实例(在此示例中),并且很糟糕。
      • @mbigras:Gilad Bracha,上述Newspeak 编程语言的设计者(Java 语言规范和Java 虚拟机规范的合著者)写了一封short blog post about static state。在 cmets 的某个地方,他说了一些有趣的话,即静态在主流编程语言(以及主流程序员)中根深蒂固,以至于他们根本无法 a) 看到它有什么问题,b) 看看你怎么能没有它永远生存。但是,像 Self 这样的语言,
      • …Newspeak、E、Scala都证明了它是可能的,特别是E和Newspeak显示了优势(在E中,摆脱静态也摆脱了环境权威,使语言能力-safe,在Newspeak中,摆脱静态状态为您免费提供强大的模块系统。
      【解决方案3】:

      我认为戴夫的措辞有点不清楚,但他在您摘录后的段落中解释了影响:

      服务即全局符号存在问题的一个很好的例子是 Resque。所有 Resque 方法都可以通过 Resque 使用,这意味着任何 Ruby VM 都只有一个可以使用的 resque。

      […]

      另一方面,如果 Resque 被实现为一个对象,而不是一个全局对象,那么任何需要访问不同 Resque 实例的代码都不必更改——它只会被赋予一个不同的对象。

      区别在于接口:使用 Resque,工具的用户“依赖”并与特定类进行接口——它们是对象,但它们是被归为全局对象的对象。这与与对象上的实例方法交互相反,其中任何其他对象都可以被替换而不依赖于对象的类。

      因此,Dave 认为,在全局(如无作用域的类定义)上使用类方法类似于使用 PHP 的全局方法。

      【讨论】:

      • 那么上面的应该改写成which means that class methods are _akin to_ global symbols吗?从符号的角度来看,我仍然很困惑是什么让类与实例方法不同。对我来说,类名在全局 namespace 中是有意义的,因此它不能被重用,但我不确定这与 symbols 的概念有何关系我>
      • @mbigras 除了 Ruby 为常量创建符号外,它与符号的概念无关。有关更多信息,请参阅此问题:stackoverflow.com/questions/5358727/…
      • @mbigras:“符号”是一个完全正常的英文单词。它在文章中的使用与 Ruby 中的 Symbol 类没有任何关系。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-22
      • 1970-01-01
      • 1970-01-01
      • 2015-06-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多