From: David Simmons Date: 2001-10-24T17:09:35+09:00 Subject: [ruby-talk:23152] Re: [SmallScript/AOS Selector Namespaces] Additional Comments I should probably mention that we could also have done all the selector namespace segregation work using interfaces. That would make it a bit more convenient for switching behavior on/off dynamically [in the same vein as David Black's system demonstrated for Ruby at the Ruby conference]. As in: Interface name: C.FooCMixin [ Method scope: C [myPrivateX ...]. ] OR for those non-smalltalkers who prefer braces as per other languages (we can also write): Interface name: C.FooCMixin { Method scope: C {myPrivateX ...}. } Then anytime we want it turned on/off for clients of the C namespace we can say: Foo.addInterface(FooCMixin) "OR" Foo.removeInterface(FooCMixin) "" For Smalltalkers that would be written identically in SmallScript as: Foo addInterface: FooCMixin "OR" Foo removeInterface: FooCMixin The performance cost for adding/removing an interface is minimal. But it will force some aspect of the VM caches to be flushed so that binding lookups will make use of the new information. I should also mention that [as per the instance specific behavior features] interfaces can be added/removed on individual objects (not just classes of objects). --- Whether the interface mixin approach is used or not, the scoped methods will still only be accessible for code with permission/access to the C namespace defined by module C. -- Dave S. [www.smallscript.org] "David Simmons" wrote in message news:nvLhJdFXBHA.2404@minos.QKS.COM... > > "Robert Feldt" wrote in message > news:Pine.GSO.4.21.0110232319250.23977-100000@ros.ce.chalmers.se... > > On Wed, 24 Oct 2001, Rich Kilmer wrote: > > > > > Question: Don't modules give you a namespace capability? > > > > > Not in the sense below. > > > > > I realize it does not in the sense that overriding a method on class > > > Array will effect the entire interpreter, but in the sense that it > > > partitions symbols (variables, classes, modules, etc). > > > > > > Are you speeking here of an ability to actually change Array, but have > > > that change only be available to the originating "namespace" and classes > > > (or modules) defined within a "namespace" are only visible to that > > > "namespace"? > > > > > > Yes, its a "namespace" in a different sense. From my understanding > > Smallscript/AOS and recent Smalltalks have this latter thing. And it > > seemed to have evolved because people were having problems with this. But > > I'm not sure of this. > > > > A sort-of scaled up Ruby/Behaviors � la David Black?! > > Background: The namespace concepts being discussed here regarding Smalltalk > were principally my work over the last ten years or so with QKS Smalltalk > and subsequently with the SmallScript language. > > Modules and Namespaces are different concepts that often overlap because > both are units of organization. In many languages these concepts are not > distinguished and that ultimately leads to problems and unnecessary > complexity. > --- > > A module is a unit of deployment and packaging (distribution units). They > may also be thought of as a unit of "ownership". > > A namespace is a unit of lexical binding/scoping. They should also be > thought of as a unit of "priviledge/permission". > > A module may contain code that extends or changes the contents of one or > more namespaces. Two or more modules may extend or change the contents of > the same namespace within a given program. Modules may reference or depend > on other modules and have a variety of prequisite/versioning issues. Modules > are best thought of as generic self describing/reflective repositories of > "things" which include code. Modules may be combined into a deployment unit > that in Microsoft.NET terms is called an assembly, but which I have > generally viewed (prior to .NET) as a rich COFF/ELF/PE/etc file. Similar to > the form a Macintosh executable takes with its resource fork. > > It may help to think of modules as being a first-class language > manifestation of projects within a classic IDE. > ----- > > I can illustrate the problem being solved as follows: > > a) Assume person A has writen some class Foo. (It might help to think of > person A as the language vendor/provider/implementor). > > b) Person B decides they want to use class Foo in their project. > > c) Person C comes along an really likes Foo and wants to add some new > features to it rather than subclassing it. Why? Because from an OO design > viewpoint it makes more sense to extend the classes behavior than to rewrite > the module that class Foo came in. Also, looking to worlds like > Microsoft.NET, they may not have the source to assembly/module to make such > changes. > > d) Person B also recognizes that it would be useful to extend Foo and make a > number of modifications. > > ----- > > At this point we have a lot of potential problems that using > "selector/message-namespaces" [which I invented for dynamic languages] will > readily and safely solve. > > Here are just a few of the obvious problems that are possible: > > 1) Person A adds new behavior to Foo which conflicts with work done by > person B or person C. > > 2) Person C decides they want to use person B's code within their program, > but the changes/extensions to Foo conflict. Or vice versa for person B using > person C's code. > ----- > > What we would like is a way to dynamically add "partitioned" behavior > (methods) to classes (or individual objects) that already exist and are > defined by someone else. > > I.e., You gave me a "Foo", we all agree it is the same class. But, I would > like to have Foo objects within my project/code do things differently than > they might in your code. And, I want my code and your code to be able to > coexist in the same running program/scriptlet/applet. > > So the example posted a few messages back where an inner-class was created > that "refined" a more general class will not work. We need the behavior to > be partitioned safely, and we need it work on all instances of the original > class. > > ----- > > To solve our problem with modules and namespaces: > > 1) Person A defines moduleA which acts as both a class and namespace. They > then create class Foo inside it. > > 2) Person B defines moduleB which acts as both a class and a namespace. They > then create their modifications packaging them in moduleB and scoping their > Foo changes to moduleB. > > 3) Person C defines moduleC which acts as both a class and a namespace. They > then create their modifications packaging them in moduleC and scoping their > Foo changes to moduleC. > > At this point everybodies work is segregated but also has the virtue they > can all be loaded at the same time within the same program. > > ModuleB will depend on ModuleA. > ModuleC will depend on ModuleA. > > When moduleB loads it will augment Foo. But since all the modifications are > "scoped" to moduleB they will not be visible to any code which does not have > access to moduleB as a namespace. > > > When moduleC loads it will augment Foo. But since all the modifications are > "scoped" to moduleC they will not be visible to any code which does not have > access to moduleC as a namespace. > > So for code which does not have access to moduleB or moduleC, but which does > have access to moduleA the Foo class will look and behave as person A > intended. > > For code that has access to moduleB the changes in moduleB will all be > accessible and will take affect accordingly. > For code that has access to moduleC the changes in moduleC will all be > accessible and will take affect accordingly. > > For code that has access to both moduleB and moduleC, the order of importing > will determine which module's changes take precedence over the other. > However, the general component design scenario is that the changes made to > Foo will be private to the implementation of componentized/modularized > services that moduleB exposes. > > Module name: A > { > Class name: Foo. > } > ---- > > Module name: B > imports: A > default-scope: B > { > Class ref-name: Foo > { > Method [ > myPrivateX > ... > ] > } > > Function [ > someCode(aFoo) > aFoo.myPrivateX /* invokes the #B.myPrivateX version */ > ] > } > ---- > > Module name: C > imports: A > default-scope: C > { > Class ref-name: Foo > { > Method [ > myPrivateX > ... > ] > } > > Function [ > someCode(aFoo) > aFoo.myPrivateX /* invokes the #C.myPrivateX version */ > ] > } > > P.S., all the braces "{" and module declarations are actually optional if > these modules were defined in separate files. I just added them for clarity > in writing the code here. > > I.e., > > "" Person C could have written their code as > Module name: C imports: A. > Method class: Foo scope: C [myPrivateX ...]. > Function [someCode(aFoo) aFoo.myPrivateX ...]. > > -- Dave S. [www.smallscript.org] > > > > > Regards, > > > > Robert