ObjectSpaces are group of objects with a global environment and their own memory area.
ObjectSpaces are organized in a n-tree thus an ObjectSpace has one parent and zero or ore children.
An object belongs to one and only one ObjectSpace. The reflection is restricted to the current ObjectSpace an object couldn't inject an object in an instance variable to a external object, or swap references of two objects that don't belong to the current ObjectSpace
Applications use more and more external plugins to add new functionalities to them. A
plugin is added inside an application and accesses all of the application objects. This is
a severe security problem. However, in a dynamically typed language and in presence of
reflective features, such approaches cannot deliver their promises. In this paper we
present ObjectSpaces. An ObjectSpace is a space containing objects with restricted reflection.
ObjectSpaces provide a natural way to scope objects and control communication between object
spaces as well as access to reflective features.
- \OSes are groups of objects. \OSes are organized in a n-tree thus an \OS has one parent and zero or more children, only the root \OS has no parent.
- An object belongs to one and only one \OS.
- Intra \OSes messages are normal messages sent, while messages between objects residing in different spaces are intercepted and controlled.
- Each \OS can have its own kernel of classes and reflective features use are restricted at the granularity of the \OS.
Since each object belongs to an ObjectSpace we've added an hidden ivar, this is not the most
efficient way to store the OS information. A nice way is to have an ObjectMemory for each ObjectSpace.
Process class is extended with a new instance variable : objectSpace.
Each newly created object will belong to the process OS. We don't share objects (now we share the classes
but we shouldn't: a method change or class change shouldn't impact the other objectSpaces).
The reflection is restricted to the space of the process, we cannot break the object encapsulations or enumerate the
Communications between two ObjectSpaces is done with sharedQueue in an async mode or can be sync. All the arguments
and results are deep copied and never shared (lazy copy is a possible optimization).
Abstract of modules papers
Modules: Encapsulating Behavior in Smalltalk
This article proposes a new view of modules - this is done in Smalltalk. Modules are a way to control the visibility of shared names. Modules also provide a way to hide the detailed collaborations among a group of Smalltalk classes. Modules can also be used to safely extend existing baseline classes.
Smalltalk can encapsulate the state of their instances, they don't encapsulate the behavior of their instances. Classes are globals in the Smalltalk system dictionary, they are all visible to all other classes.
Definition of Modules
Allen Wirfs-Brock and Brian Wilkerson in Modular Smalltalk describe features of modules:
Modules are program units that manage the visibility and accessibility of names...
A module typically groups a set of classes definitions and objects to implement some service or abstraction. A module will frequently be the unit of division responsibility within a programming team...
A module provides an independent naming environment that is separate from other modules within the program...
Modules support team engineering by providing isolated name...
In Modular Smalltalk modules are not first-class objects. It uses modules only for organizational purposes.
Modules for Smalltalk
The way to create classes in Smalltalk:
Object subclass: #File instanceVariableNames: 'directory fileId name' classVariableNames: 'PageSize' poolDictionaries: 'CharacterConstants'
They create a new module:
Object moduleSubclass: #InventoryManager instanceVariableNames: '' classVariableNames: '' poolDictionaries: ''
Add a private class in the domain:
Object subclass: #InventoryItem in: #InventoryManager instanceVariableNames: 'partNumber partName quantity' classVariableNames: '' poolDictionaries: ''
Encapsulating Private Behavior
Modules provides 3 ways of encapsulating private behavior:
- Class groups
- Baseline Class Extensions
- Private Methods
Extending Baseline Smalltalk Classes
Modules provide a safe way to extend and package changes to the baseline classes in the Smalltalk system domain.
Object moduleSubclass: #ModuleA instanceVariableNames: '' classVariableNames: '' poolDictionaries: ''
Object subclass: #SubclassB in: #ModuleA instanceVariableNames: '' classVariableNames: '' poolDictionaries: ''
String subclass: #String in: #ModuleA instanceVariableNames: '' classVariableNames: '' poolDictionaries: ''
The private String class extensions are visible to methods in both ModuleA and SubclassB, but not to classes outside of ModuleA in the Smalltalk system domain.
One drawback in that example the compiler create literals using the baseline classes: SmallInteger, String, Float, Symbol and Array.
Encapsulating Private Methods
Modules can be used to hide the private methods of a class. To do this, a public module is created with the public interface and the private method are hidden inside a private class inside the public domain.
Object moduleSubclass: #ClassA instanceVariableNames: 'privateSelf' classVariableNames: '' poolDictionaries: ''
Object subclass: #ClassA in: #ClassA instanceVariableNames: '' classVariableNames: '' poolDictionaries: ''
The ClassA module has a single instance variable: privateSelf. This is a simple proxy that hides the private behavior of the module class, all the messages are delegated to privateSelf.
Adding Modules to Smalltalk
A module class uses a ModuleDictionary for its domain, it is similar to the SystemDictionary class. Each class contained inside a module domain is associated with an EncapsulatedMetaClass rather than a MetaClass, it stores a reference to the module.
Resolving Shared Names
The visibility of the names depends on where they are located in the system. Shared names can be found in class variable pools, global pool dictionaries, and the Smalltalk system dictionary. During the method compilation, references to shared names are resolved by searching dictionaries in the following order:
class variable pool of the class and its superclasses.
pool dictionaries to which the class subscribes in the modul domains enclosing to the Smalltalk system domain.
Module domains enclosing the class up through the Smaltalk system domain
Breaking and Enforcing Module Encapsulation
Modules enclose and encapsulate their private classes, the programming tools need a way to break the encapsulation of the module to create a new class inside the module.
The method #doesNotUnderstand: aMessage to see if it is the name of a private class inside the module. This service breaks the encapsulation but it is needed by the compiler and development tools.
In order to enforce the encapsulation of a module, it can be close:
A module can provide an access to a group of private classes, by providing an accessing message as a part of the public interface.
Class Naming and Privacy in Smalltalk
Smalltalk lacks mechanisms for defining private classes and private methods. Without private classes, class naming conflicts can occur. Without private methods, encapsulation suffers. While global name spaces can help resolve class naming conflicts, first-class subsystems with private classes can resolve both problems.
The Name Space problem
Classes are globals in Smalltalk, they are all visible to all other classes, this is excessive.
SomeSuperclass subsystem: #SomeSubsystem instanceVariableNames: '' classVariableNames: '' poolDictionaries: ''
AnotherSuperclass subsystem: #SomePrivateClass in: #SomeSubsystem instanceVariableNames: '' classVariableNames: '' poolDictionaries: ''
SomeSubsystem @ #SomePrivateClass subclass: #SomePrivateSubclass instanceVariableNames: '' classVariableNames: '' poolDictionaries: ''
SomeSubsystem @ #SomePrivateClass subsystem: #SomePrivateSubsystem instanceVariableNames: '' classVariableNames: '' poolDictionaries: ''
The binary symbol @ is used as a scope resolution operator.
Private Methods and Client Contracts
In Smalltalk all the methods of a class are effectively public. Smalltalk developer indicates that a method is private by setting the category as private.
Access Implied Client Specification Private Only the implementing class Protected The implementing class and all derived classes Promised Some specific collaborating class Public Any class
The classes that collaborate closely with a subsystem often exhibit promised behavior. Thus, it would be advantageous to object system designer if object languages incorporated and enforced access mechanisms based on client specification to establish such formal contracts. Private, protected and public access can be conceived as specific kinds of promised contracts in the following manner.
Access Equivalent Contract ServerClass private ServerClass promisedTo: ServerClass only ServerClass protected ServerClass promisedTo: ServerClass any ServerClass public ServerClass promisedTo: nil
nil is used because all the root classes are derived from nil.
Private Methods and Client Contracts
This is mostly the same as the Modules: Encapsulating Behavior in Smalltalk paper. A public module with an instance variable privateSelf and an inner private class. The module provide interface like a proxy to the real instance.