This article was posted to Squeak mailing list on 27.07.1999 at 7:40 CEST by Mr. Augustin Mrazik
Here I want to tell a few words about the concepts we are following.
The Nature of Naming vs. Smalltalk
In real life, names are used for symbolic identification of real things which are known under this particular symbol in the particular context. Such things known by name are _notions_. The naming itself is a message to the receiver - he/she receives the message and understands in the particular context the particular thing - notion - under this name. Hence - a sentence (a kind of real-world expression) start with a message send to the receiver in the particular context !
In Smalltalk, expressions start with a variable or a literal. Literals are "simple data" which are instantiated in compile-time. Variables are place-holders for objects which receive the subsequent message in run-time. The variables are assigned in compile-time, i.e. they are _not_ message sends but assignments. Hence, from this point of view, early binding is used for the identification of the primary receiver of the first "normal" message in an expression (this is true for all kinds of variables - temporary, instance, class up to pool dictionaries and global variables, although the last ones are
accessed not directly, but rather via a "remote" object - an association).
The problem is that in the real life, other things may be ment under the same name in a different context. Notions related to a common context (e.g. to all golf players) are grouped into their common vocabulary which they use when talking with each other (i.e. in "their" context). Some of the words used by golf players may have a completely another meaning within an another community. Let us call such "vocabularies" to be _categories_ - a category contains notions and is able to resolve the particular name and return the relevant object.
I.e., a category is that what we call namespace. A category (namespace) is completely different from a class - while the class is used for modelling the kind of things (their common structure and behavior), categories are used for modelling the symbolic identification of localy or globaly known objects. Classes are notions by default. A category can group completely different classes (from different subtrees). Their subclasses can be located in another categories.
In fact, in real life we have too few words in our languages to describe the variety of the real world things and situations in an unambiguous way. Hence, we have to use categories - namespaces and contexts to be able to communicate what we mean to other people in the "normal way" - by natural language. If a problem arrises ("does not understand"), a "callback" from the receiver to the sender is started in order to get more information about what had been actually ment by that particular name. Most often, this information is provided by explicit naming the "vocabulary" from which the used word had been taken.
Hence, the real world is polymorphic also in naming the receivers, not only in their responses to the subsequent messages (methods). This enables to achieve the description of the variety of things and situation in real life with the limited vocabulary of natural languages.
Also, in real worls namespaces are being specialized. If you have a common namespace for al sciences, then it may be specialized by a namespace for mathematic, then for algebra etc. etc. In each of the sub-namespaces, all notions from the super-namespace are valid (unless redefined) + new notions specific to this particular namespace are added. In a neighbour namespace (with common parent), some names may have another meaning.
In the pink plane of Squeak Namespaces, there is the intention not to change the way how Smalltalk works but to offer the namespaces which can help to model "categories" - real-world vocabularies, in particular to achieve the polymorphism of global variables and pool dictionaries. The basic approach is almost the same as described in the paper from 1992:
- Namespace is a subclass of Dictionary; namespaces enable to hold objects under different names; Smalltalk is the sole instance of SystemDictionary which is subclass on Namespace (it's a special namespace which also represents the system as a whole),
- a namespace can inherit from another namespace - the namespaces build a directed acyclic graph (multiple inheritance); if you are looking for a notion in a particular namespace, you "understand" all the notions from all superodered namespaces; I prefer inheritance to "importing namespaces" - with inheritance we can model the _specialization_ of existing namespaces, where several different specializations may co-exist beside each other and provide e.g. alternate objects for the same naming; with multiple inheritance, you can always join all namespaces you intend to use to be parents of your "working" namespace - e.g. after having Smalltalk divided into namespaces Kernel, Numeric, Collections, Compiler, ..., you can create namespaces Development and RunTime - the RunTime namespace simply would not include compiler, browser etc. while the other would,
- Smalltalk is the default root of namespaces; another roots are possible, but they must be accessible from Smalltalk or some of its sub-namespaces; such separate roots do not inherit anything from Smalltalk, e.g. you may build a completely different collections and use them in your applications,
- global variable CurrentNameSpace is added in Smalltalk which is always set to some of the namespaces; in this namespace expressions in workspace are compiled; it may be used and changed by applictions,
- the path in the namespaces is identified by subsequent message sends, e.g.
MyApplication Interfaces MyClass new ...
(Smalltalk Set = MyApplication Collections Set) ifTrue: [.....
- classes know their namespaces - variable 'motherNameSpace' is added to Class; all methods are compiled in this namespace, incl. inherited globals; when a class is moved between namespaces, it has to be recompiled; classes may be subclassed in another namespaces, subclass may mave the same name as its superclass (if in anoyther namespace)
CurrentNameSpace := MyApp.
Smalltalk Set subclass: #Set ...
In the blue plane, static vs. dynamic identification of the primary receiver in expressions is the major question (beside namespace functionality of the pink plane) - the SELF-like messages. Some thoughts in this direction:
- first token in an expression should be a message send to thisContext which would find what it means;
- temporary variables are the "attributes" of the context - they could be known (inherited) in all subcontexts; they are accesed and modified only by message sends, e.g.
name = 'Peter' ifTrue: [...
name: 'Peter' ..... (which means "thisContext name:...")
- instance vars are "attributes" of the object in the same way,
- class vars should be similar "attributes" of the class while pool dictionaries would be substituted by namespaces,
- globals are entries in namespaces,
- literals: even literals could be understood as message send to thisContext and interpreted in the right way, e.g.
means an integer to be send a message #factorial for everybody but Bill - he would send it rather to windoze
All this are really just thoughts because it would impact the readability of the code for "all smalltalkers" too much - not ot talk about performance, ... Hence, so far from the blue plane we are implementing the identification of global variables only (as message send to self, not to thisContext).
Blue plane (even with globals only) leads to a full polymorphism and hence higher reuse: even the same method may run completely different in applications running in different namespaces (since globals in ti wil be looked up in run time). Hence you can easily plug-in new libraries, test your applications with each of them, choose the best one etc.