From: David Simmons Date: 2001-11-25T13:39:29+09:00 Subject: [ruby-talk:26422] Re: Selector Namespaces: A Standard Feature for Smalltalk? "Panu Viljamaa" wrote in message news:3C004B97.53B55D50@fcc.net... > Amongst the wealth of information behind the links you gave, it is hard to find > the actual definition of "selector namespaces". Could you - or someone else - > give a one paragraph explanation and example please ? Look at slides 6-21 of Waldemar's PowerPoint talk on "JavaScript 2.0" [most of which is on the topic of selector namespaces]. http://ll1.mit.edu/horwat.ppt. Waldemar Horwat [waldemar@netscape.com] has been working on the design of JavaScript 2.0 for Netscape. I will also endeavor to provide a concise SmallScript [www.smallscript.org] example (replicating Waldemar's slide example): NOTE: Code snippets are presented in chronological development order. ---------------------------------------------- Module/package with a component v1.0.0.0 ---------------------------------------------- Module name: BitTracker version: 1.0.0.0. Class name: Data fields: author, contents { Method [ save ... ] } ------------------------------ 3rd party (or web page script): ------------------------------ Requires module: BitTracker. "version constraints elided" Class name: Picture extends: BitTracker.Data fields: palette { Method [ size ... ] } Function [ orientation ^(d.size.h >= d.size.v) ?: 'Landscape' : 'Portrait'. ] ---------------------------------------------- Module/package with a component v2.0.0.0 ---------------------------------------------- Module name: BitTracker version: 2.0. "extra 0's not required" Class name: Data fields: author, contents { Method [ save ... ] Method [ size ... ] } Function [ store(d) if (d.size > limit) storeOnSlowDisk(d). else storeOnFastDisk(d). ] ==== At this point we clearly have a problem. Waldemar's slides present discussion of the general issues and non-solutions so I will not repeat them here. The problem is that #size is defined in the subclass , but it is also defined in v1.1 of . Those definitions are clearly unrelated. The version appears to return an of some form, whereas the version appears to return a size in some units such as bytes. We can also assume, as with many component systems, that the 3rd party could not anticipate this conflict and vice-versa. This is typically characterized as 3rd party late integration (or just-in-time-integration). We can also assume that that the #save method in will invoke the #store method in the module. Next we can assume that someone allocates a objects and at some point that instance is sent the message #save. We can also assume that the inherited #save method will eventually invoke the function #store. We can see that the #store function expects to invoke the variant of #size and will, hopefully, cause a runtime exception when it gets an rather than (for use in the expression "d.size > limit". ==== What we would like is some mechanism to ensure that the two different versions of #size remain independent. Selector namespaces directly solve this issue. In SmallScript (I can't speak with certainty about JavaScript 2.0), message selectors are instances of . As such they have both: a string-name, and a namespace-scope. Classes are namespaces in SmallScript [and we all know everything is an object in Smalltalk/SmallScript]. So, whenever you send a message the default-scope for the selector is the method-dictionary (class) in which the method was defined [this isn't strictly what happens in the SmallScript implementation because there are other binding predicate factors, but it is sufficient for this presentation]. Therefore, we can observe that the "d.size" issued from the #store(<>) function in will issue all its messages (by default) with selectors whose scopes are set to the namespace. I.e., #size will actually be #BitTracker.size We can also observe that the class is (in my example) defined in the default-namespace for a script. Which is effectively an anonymous namespace. So the #orientation method will issue #DefaultProject.size or some equivalent anonymous name. --- Now the question becomes, how do we make use of this fact? Depending on our design goals, there are a number of "well-factored" solutions available. But we need to know about one more feature; scoped methods. Messages bound to calling context namespaces is really only half the story. The other half is to recognize that method objects themselves are also identified by selectors. Which is how the runtime/compile-time machinery maps messages to methods. In SmallScript, methods can actually have up to two names (although they have to have the same arity -- arg-count). The option for an alternate name is to facilitate cross-language interop between Smalltalk keyword selector and the common imperative/parenthetical name() form we see in almost every other language [especially important for using the SmallScript for .NET option]. But that is a whole other topic which would also involve discussion of SmallScript's selector aliasing facilities. It also worth noting that namespaces in SmallScript support both lexical (nested) inheritance, and explicit import inheritance yielding namespaces with MI characteristics. The same parallel is true for classes and mixing in [implementations contained in] interfaces in SmallScript Implied here is that there must be a deterministic order for MI (namespace ordering [which is distinct from} behavior/type ordering). Finally, I'll add that is just a subclass of which is a subclass of . And, since classes are namespaces, interfaces are namespaces. So you can scope to an interface or any other class. When combined with safe/tainted method/class attributes we get sandboxes in SmallScript. It is also where the concept of dynamic runtime enforcement of family/private methods starts to happen [with a little subtle but transparent magic involving the use of metaclasses -- and optionally even more rigorously privatized with the non-inheritable method attribute]. "" Which can be declared as Method scope: private [...] When a method is compiled, its selector is always given a default scope of the outermost (global) namespace. This can be modified based on attribute settings in the surrounding context in which it was declared [such as declaring some other default-scope for its enclosing module, class, etc]. If a method's selector has a global scope, then any message selector with the same name can bind to that method (regardless of the calling selector's scope). But, if the method's selector is not globally scoped, then we say that the method is "scoped" to the namespace of its selector. Which is where the term "selector namespaces" really comes into play. In this latter case, the method can only be invoked (will only bind) if the calling message's selector's namespace has access to the implemented method's selector's namespace. Furthermore, this is performed on a best fit basis; which means that if there are multiple (method) implementations available the best fitting implementation will be chosen based on all the binding predicates [selector namespace fit being just one predicate]. In classic Smalltalk the only predicates are the selector-name and the message receiver-class. SmallScript offers many other predicates and provides an extensible predicate mechanism as part of its AOP/MOP/Managed-Object facilities. --- So, armed with that knowledge we can revise the code examples slightly and fix the problem for almost any scenario. In this case I will exactly follow Waldemar's example for consistency with the JavaScript 2.0 slides [otherwise I would probably have written a different solution]. ---------------------------------------------- Module/package with a component 2.0 ---------------------------------------------- Module name: BitTracker imports: v2 version: 2.0. "extra 0's not required" Namespace name: v2. Class name: Data fields: author, contents { Method [ save ... ] Method scope: v2 [ size ... ] } Function [ store(d) if (d.size > limit) storeOnSlowDisk(d). else storeOnFastDisk(d). ] ==== With this revised version we have scoped the version of #size to only be invocable from callsites that have access to the namespace. Which, the function #store(<>) has via the "import:" attribute on the class. So unless a client explicitly references the namespace they will not conflict with the #size method. My reason for saying I would have written it differently is that the namespace is not particularly unique or protected either. But that would be a different presentation of issues and so we will stop here with a SmallScript solution that is parallel to Waldemar's JavaScript 2.0 slides. P.S., if you want to understand this better and play with the concepts (especially in light of optional typing, mult-methods, around-before-after methods, sandboxing, etc) then sign up for the SmallScript Technology Preview Seed at www.smallscript.org. -- Dave S. [www.smallscript.org] > > Thanks > -Panu Viljamaa