Smalltalk 中的内部类

发布于 2024-12-05 15:10:56 字数 247 浏览 0 评论 0原文

我想知道为什么smalltalk不使用java风格的内部类。这种机制有效地允许您在需要时随时随地定义新类的新实例。当您需要一个符合某些特定协议的对象但又不想为它创建一个普通的类时,它会很方便,因为它的临时和本地性质非常特定于实现。 据我所知,这可以很容易地完成,因为子类化的语法是标准消息发送。你可以将 self 传递给它,这样它就有了“外部”对象的概念。唯一的问题是匿名性 - 该类不应该出现在对象浏览器中,并且当没有它的实例存在时必须进行垃圾收集。 问题是:有人想到过这个吗?

I wonder why smalltalk doesn't make use of java-style inner class. This mechanism effectively allows you to define a new instance of a new class, on-the-fly, where you need it, when you need it. It comes handy when you need an object conforming to some specific protocol but you don't want to create a normal class for it, because of its temporary and local nature being very implementation specific.
As far I know, it could be done easily, since syntax for subclassing is standard message sending. And you can pass self to it so it has the notion of the "outer" object. The only issue is anonymousity - the class should not be present in object browser and must be garbage collected when no instances of it exit.
The question is: Has anyone thought of this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

尐籹人 2024-12-12 15:10:56

这里确实有两个答案:

1 - 是的,创建自动进行垃圾收集的匿名类并不难。在 Squeak 中,它们被称为“uniclasses”,因为典型的用例是向单个对象添加方法。使用此功能的系统有 Etoys 和 Tweak(尽管在 Etoys 中,由于历史原因,类实际上被放入 SystemDict 中)。以下是我最近使用的一些 Squeak 代码:

newClass := ClassBuilder new
    newSubclassOf: baseClass
    type: baseClass typeOfClass
    instanceVariables: instVars
    from: nil.
baseClass removeSubclass: newClass.
^newClass

通常,您会添加一个方便的方法来执行此操作。然后您可以添加方法并创建一个实例,当所有实例都消失时,该类也将被GC。

请注意,在 Java 中,类对象不会被 gc 处理 - 内部类的编译方式与常规类完全相同,只是被编译器隐藏。相比之下,在 Smalltalk 中,这一切都发生在运行时,甚至是为此类编译新方法,这使得它的效率相对较低。有一种更好的方法来创建匿名预编译行为,这给我们带来了答案 2:

2 - 尽管它并不难,但在 Smalltalk 中很少使用。原因是 Smalltalk 有很多更便捷的机制。 Java 中的内部类最常用于动态构建实现特定接口的方法。内部类声明只需要让编译器满意类型安全即可。 在 Smalltalk 中,您只需使用块闭包。这使您可以动态创建可以传递的行为。系统库的结构采用了块闭包的方式。

我个人从来不认为 Smalltalk 需要内部类。

There are really two answers here:

1 - Yes, it is not hard to create anonymous classes that automatically get garbage collected. In Squeak they are called "uniclasses" because the typical use case is for adding methods to a single object. Systems that use this are for example Etoys and Tweak (although in Etoys the classes are actually put into the SystemDict for historic reasons). Here's some Squeak code I recently used for it:

newClass := ClassBuilder new
    newSubclassOf: baseClass
    type: baseClass typeOfClass
    instanceVariables: instVars
    from: nil.
baseClass removeSubclass: newClass.
^newClass

Typically, you would add a convenience method to do this. You can can then add methods, and create an instance, and when all instances are gone, the class will be gc'ed too.

Note that in Java, the class object is not gc'ed - an inner class is compiled exactly like a regular class, it's only hidden by the compiler. In contrast, in Smalltalk this all happens at runtime, even the compiling of new methods for this class, which makes it comparatively inefficient. There is a much better way to create anonymous precompiled behavior, which brings us to answer 2:

2 - Even though it's not hard, it's rarely used in Smalltalk. The reason for that is that Smalltalk has a much more convenient mechanism. Inner classes in Java are most often used for making up a method on the fly implementing a specific interface. The inner class declaration is only needed to make the compiler happy for type safety. In Smalltalk, you simply use block closures. This lets you create behavior on the fly that you can pass around. The system libraries are structured in a way to make use of block closures.

I personally never felt that inner classes were something Smalltalk needed.

め可乐爱微笑 2024-12-12 15:10:56

如果您正在考虑使用内部类进行测试,那么您还可以看看 ClassFactoryForTestCase 类

If you are thinking of using inner classes for tests, then you can also take a look to the class ClassFactoryForTestCase

冷情妓 2024-12-12 15:10:56

在smalltalk 中创建匿名类是小菜一碟。
更重要的是,任何具有 3 个实例变量正确设置为:其超类、方法字典和实例格式的对象都可以用作类(具有实例)。
所以,我不明白这里的问题是怎样的。

如果您谈论工具支持,例如浏览或导航此类中包含的代码,那就是另一回事了。因为默认情况下系统中的所有类都是公共的,并且系统字典是它们的平面命名空间(是的,某些实现具有命名空间)。这个简单的模型在大多数情况下都运行良好。

Creating an anonymous class(es) in smalltalk is a piece of cake.
More than that, any object which has 3 its instance variables properly set to: its superclass, method dictionary and instance format could serve as a class (have instances).
So, i don't see how the problem here.

If you talking about tool(s) support, like browsing or navigating code which contained in such classes, this is different story. Because by default all classes in system are public, and system dictionary is a flat namespace of them (yes , some implementations has namespaces). This simple model works quite well most of the times.

抱猫软卧 2024-12-12 15:10:56

我非常确定这可以通过围绕类和元类协议进行一些黑客攻击来完成。对于那些有更多 Java 经验的人来说,这个问题经常出现,他们对 Smalltalk 变得很感兴趣。尽管如此,由于内部类尚未实现,我认为这表明大多数 Smalltalk 用户认为它们不可用。这可能是因为 Smalltalk 有块,它以更简单的方式解决了许多(如果不是全部)导致 Java 引入内部类的问题。

I am pretty sure it could be done with some hacking around the Class and Metaclass protocol. And the question pops quite often from people who have more experience in Java, and Smalltalk becomes interesting to them. Since inner classes have not been implemented inspite of that, I take it to be the sign that most Smalltalk users do not find them usable. This might be because Smalltalk has blocks, which in simpler manner solve many if not all problems that led to the introduction of inner classes to Java.

帅哥哥的热头脑 2024-12-12 15:10:56

(a) 您可以发送消息以从另一个类的方法内部创建一个新类

(b) 我怀疑从内省系统中隐藏生成的类有什么好处

(c) 在 Java 中使用内部类的原因是因为没有一流的功能。如果你需要在Smalltalk中传递一段代码,你只需传递一个块即可。您不需要将其与其他类型的对象包装在一起来执行此操作。

(a) You could send the messages to create a new class from inside the method of another class

(b) I doubt that there is any benefit in hiding the resulting class from the introspection system

(c) The reason you use inner classes in Java is because there are no first-class functions. If you need to pass a piece of code in Smalltalk, you just pass a block. You don't need to wrap it up with some other type of object to do so.

满栀 2024-12-12 15:10:56

问题(至少在 Squeak 中)源于缺乏清晰的关注点分离。创建您自己的子类并将其放入私有 SystemDictionary 中非常简单:

myEnv := SystemDictionary new.
myClass := ClassBuilder new
    name: 'MyClass'
    inEnvironment: myEnv
    subclassOf: Object
    type: #normal
    instanceVariableNames: ''
    classVariableNames: ''
    poolDictionaries: ''
    category: 'MyCategory'
    unsafe: false.  

但即使您将该类放入您自己的 SystemDictionary 中,“MyCategory”类别也会添加到系统中导航(可通过打开浏览器进行验证),而且 - 更糟糕的是 - 未创建类组织者,因此当您导航到 MyClass 时,您会得到一个 nil 指针。

从理论上讲,这当然不是不可能的。目前,该工具适用于全局可见的类定义的单个池。

The problem (in Squeak at least) comes from the lack of a clean separation of concerns. It's trivial to create your own subclass and put it in a private SystemDictionary:

myEnv := SystemDictionary new.
myClass := ClassBuilder new
    name: 'MyClass'
    inEnvironment: myEnv
    subclassOf: Object
    type: #normal
    instanceVariableNames: ''
    classVariableNames: ''
    poolDictionaries: ''
    category: 'MyCategory'
    unsafe: false.  

But even though you put that class in your own SystemDictionary, the 'MyCategory' category added to the system navigation (verifiable by opening a Browser), and - worse - the class organisers aren't created, so when you navigate to MyClass you get a nil pointer.

It's certainly not impossible, theoretically. Right now the tooling's geared towards a single pool of globally visible class definitions.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文