【问题标题】:Is it possible to extend an individual object in Smalltalk是否可以在 Smalltalk 中扩展单个对象
【发布时间】:2012-12-21 05:02:15
【问题描述】:

我正在研究 Smalltalk 反射,我想知道是否可以像在 Ruby 中那样扩展单个对象。我的意思是只有特定对象才会响应的选择器。

这里有一些 Ruby 代码说明了我的意思。 澄清一下:在 Ruby 中,这会为此对象打开一个虚拟类,并使用新定义对其进行扩展。这里最重要的部分是类定义没有任何变化!

o = Object.new
o.instance_eval {def foo;puts "foo";end}
o.foo #=> "foo"

#however this will fail:
m = Object.new
m.foo #=> NoMethod error

更具体地说,我的问题是这在标准 Squeak/Pharo 或其他 smalltalk 实现中是否可能,而无需添加大量结构或代码来实现这一点。换句话说,Smalltalk 中存在规则反射特征。

例如,可以添加方法、删除方法、将新代码编译到类中、更改实例变量等等,但我还没有找到扩展单个对象的方法。

Test addInstVarNamed: #var.
Test compile: 'var ^var'.
t:= Test new.
Test instVarNames.
t instVarNamed: #var put: 666. 
t var. #=> 666

如果答案是否定的,请解释原因。我不是要解决这个问题,而是要理解为什么它不在 smalltalk 中。

【问题讨论】:

    标签: reflection smalltalk pharo squeak


    【解决方案1】:

    在 Smalltalk 中具有特定于实例的行为基本上涉及更改指针类和原始调用。 Bob Hinkle、Vicki Jones 和 Ralph E. Johnson 的 "Debugging Objects" 文章发表在 Smalltalk 报告,第 2#9 卷,1993 年 7 月至 8 月,包含所有解释。

    我已经移植了 Bob Hinkle 于 1995 年为 VisualWorks 2.0 发布的版本中的原始 轻量级类 代码。 VisualWorks 源代码包含分为三个包的代码,分别名为 "ParameterizedCompiler""Breakpoint""Lightweight"。这种划分的原因是希望拥有单独的和可重用的功能。他们都在 OOP 期刊上发表了单独的文章。

    我的Squeak/Pharo port 包含一个“实例浏览器”,它基于OmniBrowser(以及更多documentation here)框架,让您可以通过经典的 Smalltalk 浏览器 UI 浏览和修改添加轻量级行为的实例。它可以在最新的 Squeak 4.x 版本中运行,几乎不需要任何努力。不幸的是,Pharo 的基础架构与

    在 VisualWorks 中,由于 VisualWorks GUI 从 2.0 到 7.3 的深刻变化,大多数用于管理轻量级类的工具都没有包括在内。如果有人有兴趣,我可以上传大众 7.3 的包裹

    测试轻量级类功能的基本脚本是:

    | aDate |
    aDate := Date today.
    aDate becomeLightweight.
    aDate dispatchingClass 
            compile: 'day ^42' 
          notifying: nil 
             ifFail: [self error].
    aDate day inspect
    

    【讨论】:

    • ...那是我一直在寻找但找不到的论文。 +1!
    【解决方案2】:

    在 Smalltalk 中,没有内置的方式来以这种方式执行特定于实例的行为。 Smalltalk 坚持每个对象属于一个类的原则,其行为和状态形状取决于类。这就是为什么您可以轻松更改类(添加 inst 变量、编译新方法等),但这意味着将行为更改为所有实例。 然而,有不同的方法(根据 Smalltalk 风格)来实现特定于实例的行为,例如轻量级类,其想法是为特定实例创建一个特殊的(轻量级)类,并用自定义的类替换原始类一。因此,每个“特殊”实例都有一个特殊的类。 Digitalk St 中的 AFAIK 调度机制更加灵活,可以轻松实现基于实例的行为(参见第 4 个链接)。我会在这里留下一些您可能会觉得有用的链接:

    HTH

    编辑: Hernan 发布的链接(Hinkle, Jones & Johnson 的“Debugging Objects”)是我所指的但找不到的链接。

    【讨论】:

    • 我已经阅读了第一个链接,但仍然很难像您刚才解释的那样弄清楚它背后的真正想法。我一定会查看其他链接。优秀的答案
    • 也许截屏视频(3d 链接)会让你有更好的理解。我试图找到详细解释轻量级类如何工作的 the 论文,但我似乎找不到它。给我几分钟:)
    • 对不起,我还是找不到。我添加了第 5 个链接,其中很好地解释了方法查找在 Smalltalk 中的工作原理以及用于操纵消息传递的不同技术。它还引用了轻量级类方法。
    【解决方案3】:

    Squeak Etoys 大量使用对象特定的行为和状态。这被实现为“uniclasses”。当你为一个 Etoys 对象(Player 类的实例)创建脚本时,该对象的类将被更改为“uniclass”,即 Player 的唯一子类,它可以有自己的方法(对应于 Etoys 脚本)和实例变量(对应Etoys用户变量)。

    其他基于 Squeak 的项目使用“匿名”单类,这些单类未在其超类中列为子类。这意味着它们几乎是不可见的,因为它们不会出现在系统浏览器中,例如(而 Etoys 风格的 uniclass 确实会出现在浏览器中)。

    【讨论】:

      【解决方案4】:

      colleage 一直在为 Pharo Smalltalk 开发一个名为 Bifrost 的新反射 API。你可以查看Bifrost project的页面。

      他的方法在其核心推动了特定于实例的适应。一切都是通过将元对象绑定到常规对象以适应它们而发生的。较低级别的元对象可以组合成较高级别、粗粒度的元对象,这些元对象定义了合理的适应,例如一个分析元对象,它将测量对目标对象的每次调用所花费的时间。

      【讨论】:

        【解决方案5】:

        正如@ewernli 指出的那样,Bifrost 基本上使 Smalltalk 成为一个以对象为中心的反射系统。所有反射更改首先针对对象,而不是具有与类的混合机制。 您仍然可以在以对象为中心的反射之上进行所有传统的类反射。 我认为与这种新方法相关的是我们发现的一些应用程序可以改进我们开发和感知实时系统的方式:

        Object-centric debugging 完全改变了我们的调试方式,专注于对象并允许开发人员保持与活动对象交互,而不必在源代码级别插入条件断点。

        Talents 是可组合的动态重用单元,类似于特征,但用于对象。 还有更多的应用程序。

        【讨论】:

          【解决方案6】:

          据我所知,在 Ruby 中,方法字典附加到对象。

          在 Smalltalk 中,方法字典绑定到 Class 对象,因此,在普通 Smalltalk 图像中,您不能编写类似 eigenclass 的东西。

          话虽如此,原型库有几个:this question's answers 提到不少。

          【讨论】:

          • 我认为你实际上在 Ruby 中两者都有。它们也绑定到 Class 对象,但扩展对象时创建的特征类是从类的特征类扩展的新的单独类。但无论如何,我会检查链接谢谢!
          猜你喜欢
          • 1970-01-01
          • 2020-08-01
          • 1970-01-01
          • 2020-12-22
          • 2018-08-16
          • 1970-01-01
          • 1970-01-01
          • 2019-01-25
          • 2010-12-21
          相关资源
          最近更新 更多