开发者

inner classes in smalltalk

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" ob开发者_StackOverflow中文版ject. 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?


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.


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


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.


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.


(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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜