是否可以在Smalltalk中扩展单个对象

时间:2013-01-07 12:55:48

标签: reflection smalltalk pharo squeak

我正在做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

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

6 个答案:

答案 0 :(得分:10)

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

我已经从1995年由Bob Hinkle为VisualWorks 2.0发布的版本中移植了原始的 Lightweight classes 代码。 VisualWorks源代码包括分为三个包的代码:“ParameterizedCompiler”“Breakpoint”“Lightweight”。这种划分的原因是希望具有独立和可重复使用的功能。所有这些都在OOP期刊上有单独的文章。

我的Squeak/Pharo port包含一个“实例浏览器”,基于OmniBrowser(以及更多documentation here)框架,可让您浏览和修改通过经典添加轻量级行为的实例Smalltalk浏览器UI。它可以在最新的Squeak 4.x版本中运行,很少或没有努力。不幸的是,Pharo的基础设施从版本<= 1.2变化很大,因此可能需要一些工作才能使用最新版本。

Instances Browser with an instance modified

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

Instances Browser in VisualWorks

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

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

答案 1 :(得分:7)

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

HTH

编辑: Hernan发布的链接(Hinkle,Jones&amp; Johnson的“调试对象”)是我所指的那个找不到的链接。

答案 2 :(得分:4)

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

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

答案 3 :(得分:3)

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

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

答案 4 :(得分:2)

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

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

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

答案 5 :(得分:1)

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

在Smalltalk中,方法字典绑定到Class对象,因此,在vanilla Smalltalk图像中,您无法编写类似本征类的东西。

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