Dave Harris wrote:
> > Not in the way I'm seeing it. The "package" wouldn't have anything to > > do with it -- it's not in command, *I* am. > > I was thinking that adding extra functionality to String might be part of > the purpose of the package. The package's author ought to have a way to > indicate which methods were intended for public use, and which were not. I > don't think anyone other than the author can make that distinction, > because "public" is basically a promise from the author that it will not > change. Well, I don't really have an answer to this, because you are assuming that selector namespacing is part of the available toolkit, and I don't see how to do that. However, if we do assume that the facility is available, then the issue you raise doesn't seem to be very important. That's to say that almost *any* way of indicating which methods were intended for public consumption would work. One that could easily be "read" from outside the package, before/while loading it would be better, but since I see the facility being used only infrequently, I'd have no particular problem with my having to specify which methods *I* wanted to allow the package to "export" manually, and on a case-by-case basis. I don't see the problem as important enough to warrant anything more than whatever ad-hoc, or informal, indicator happened to be handy (the package comment, for example). If it did turn out to be worthwhile formalising the mechanism, then it'd just be a matter of settling on, and standardising, whatever ad-hoc technique was most popular (or in some other way "best"). > > which might be (but there's no real need) abbreviated to something like: > > > > Namespace current > > import: #SomeClass > > from: 'Odds and Ends' > > as: #MyNameForSomeClass. > > The abbreviation is much easier to read :-) Yes, and I've got nothing against it. I did want to stress the unabbreviated version, though, because I didn't want to be misunderstood as advocating some sort of quasi-declarative scheme. > > > In any case, asking the consumer to sort it all out means we can't > > > very well load classes dynamically, on an end-user's machine > > > > I don't see why not. Loading classes dynamically has to happen under > > the command of some code, and that code could import packages into > > restricted namespaces as easily as it can import them into the > > global namespace. > > That's true if your only supported policy is: everything is private. It > can't guess which names are intended to be available to other packages. I still don't see your point. Say that I, the developer of the deployed application(s), determine that I want to include some third party's code in my distribution, but in a restricted way. If I *weren't* doing incremental distribution, then I'd just script the loading of the packages into the/a restricted namespace. But can't I do just the same thing if I'm doing incremental deployment too ? I just ship the script as part of the update; after all I'll need some such script (or similar) anyway, in order to tell the installation to update itself. > > I any case, the particular scheme that *I* was talking about (as > > opposed to the thread in general) isn't so much an attempt to design > > an ideal namespace scheme, as a way to avoid having namespaces at all. > > To me it sounded like a very simple scheme, rather than the absence of a > scheme (which is what we have now). Fair enough. A still better way of presenting it might be as a way of packaging the functionality needed for the *implementation* of namespaces, in a way that doesn't add namespaces to the core of the language. -- chris |
[hidden email] (Chris Uppal) wrote (abridged):
> > > > In any case, asking the consumer to sort it all out means we can't > > > > very well load classes dynamically, on an end-user's machine > [...] > I still don't see your point. The scenario I had in mind was when the choice of 3rd party packages to be loaded was made by the end-user. As such it cannot be fully anticipated by the programmer in advance, so the programmer cannot write a script. > That's to say that almost *any* way of indicating which methods were > intended for public consumption would work. I think that any solution has to deal with the full gamut of complexity, including having a run-time presence (ie not just load-time), and will end up being equivalent to selector namespaces in semantics. Perhaps it can be done without special syntax, but I think having syntax reflect semantics is often better. -- Dave Harris, Nottingham, UK |
In reply to this post by cstb
cstb wrote:
> > (3) In your code, always refer to > transformer via the local method > > (self transformer) selectorWhatever > I think I see your point, but I'm not quite convinced that the added encapsulation is worth the added complexity (then again I may not quite get what your example correctly) . There's some added complexity in the above. First of all every reference to a global/class now gets longer (if I get you correctly, right?). I've tried something similar over the years but somehow the added encapsulation doesn't seem to be worth the added complexity. Whereas the rule "Instead of accessing a class directly, always call a method that returns it" seems to be *easy to grasp*, and *easy to remember*. > ... > Advantages: Encapsulates further, as client > doesn't need to know the class > side methods, The above seems to indicate that I perhaps didn't explain my intentions clearly. I didn't say - nor was it my intention - that the method should be a "class side" method at all. Rather, I tried to indicate by the example that it should be a method that one sends to 'self'. Sending something to self is the closest thing to "encapsulation" I can think of. Cheers -Panu Viljamaa |
In reply to this post by Chris Uppal-3
Chris Uppal wrote:
I recently (just for fun/interest in how it'd turn out) chose to implement a > small toy project in a style where all responsibility for creating objects (and > hence all references to classes) were the responsibility of a single > system-wide object. Right. But that is *your* system-wide object. What if you want to load some-one else's code into your image? -Panu Viljamaa |
panu wrote:
> I recently (just for fun/interest in how it'd turn out) chose to > implement a > > small toy project in a style where all responsibility for creating > > objects (and hence all references to classes) were the responsibility > > of a single system-wide object. > > Right. But that is *your* system-wide object. > What if you want to load some-one else's code > into your image? The relevance is that since "my" classnames are hidden, and there is only the one "global" identifier, all the actual classnames can be (and are) long and descriptive without impacting clients of my code (if there were any). That in itself makes it highly unlikely that I/they will experience clashes. Also the fact that all (just about) references to classnames from inside the module are centralised in the 'Music' object means that changing them is extra specially easy -- should the need ever arise. There is, of course, no way that I can write *my* code such that it reduces the possibility of name clashes between two separate third parties. Well, not unless I go ahead and implement my "non-intrusive namespaces" suggestion from elsewhere in this thread -- I'm getting increasingly tempted to have a pop at it, it looks quite easy to do a bare-bones (little/no tools support, global identifiers only, no selector namespaces) implementation. -- chris |
In reply to this post by Panu Viljamaa-5
panu wrote:
> > cstb wrote: > > > > (3) In your code, always refer to > > transformer via the local method > > > > (self transformer) selectorWhatever > > > > I think I see your point, but I'm not quite > convinced that the added encapsulation is > worth the added complexity (then again I may > not quite get what your example correctly) . Just noting that, whereas you put the responsibility for answering an actual receiver in an instance method, I suggest moving it to the class side (whenever it will answer aClass). So the trace is (self transformer) selector --> (self class transformer) selector --> ActualReceiver selector The second line of the trace is the 'added complexity', but if you do this all the time, its very easy to follow. In fact, it gets exceptionally easy, as we'll see below. > There's some added complexity in the above. > First of all every reference to a global/class > now gets longer (if I get you correctly, right?). If by longer you mean takes one more indirection hop then yes, it is longer. But I wouldn't agree that this increases the 'complexity', either formally or informally. You can obviously ignore the 'cost' of the extra indirection, as one doesn't refer to another class very often, so the extra time is minuscule. In the rare cases that this isn't true, either a) you should think about refactoring, as someOfThisCode wants to be in that other class or b) you've got an otherwise working solution, but which fails to meet some performance requirement AND profiling the code tells you that removing this particular indirection will have a significant effect toward speeding it up. > > Whereas the rule "Instead of accessing a class > directly, always call a method that returns it" > seems to be *easy to grasp*, and *easy to remember*. > My version of your rule, then, is two parts: 1) "Instead of accessing a class directly, always ask yourself which class to use. (self whichClassToUse) whateverTheSelectorIs... 2) "When you are asked which class to use, always query your own class side for the answer. self>>whichClassToUse ^self class whichClassToUse self class>>whichClassToUse ^TheActualClass > > ... > > Advantages: Encapsulates further, as client > > doesn't need to know the class > > side methods, Meaning - [and not that you do this, just that one shouldn't] Don't directly refer to your own class side methods using CapitalizedSelectors, (as is sometimes suggested) - instead, always refer to a forwarding method that is defined on the instance side. Result: 1) Scanning some code, you see a reference: self thingAmaJig doSomething You don't know about thingAmaJig, so you look for it (in the all categories list) - and find it in the category 'accessing class'. You now know (without looking at it) that it is either answering a constant, or a collaborating class, and decide you can safely ignore that detail for now. You return to scanning the original code. 2) You want to modify a class, changing a collaborator. You go to the class side, and select the category 'collaborators'. You look at all the methods, and one of them just answers ThingAmaJig. That's the guy you want to swap out. The name of the method answering ThingAmaJig is #thatThingYouUse, so you browse local senders of #thatThingYouUse, and you get a list of every place this class is using ThingAmaJig, i.e. by looking at just these spots in the code you'll know the actual protocol being used with ThingAmaJig. So now you know - you can indeed replace ThingAmaJig with NewFangledCoolness because (having written it, you happen to recognize) the latter also defines all the methods that are actually being used on ThingAmaJig -- used *by this class*. You do not care about any other methods ThingAmaJig might define, because only the ones listed in the browser window right now are used *here*, in the class you want to change. The other 6,432 methods defined on ThingAmaJig (a god class, obviously) are not used here at all, so you don't have to bother defining them on NewFangledCoolness. You don't even have to read them. Lucky you. Nice convention. > ... > > Sending something to self is the closest > thing to "encapsulation" I can think of. That's right. There's only one thing closer, which is - don't send to anyone - i.e. reference an instVar directly. But I wouldn't advise doing this *unless* you happen to have a reasonable refactoring tool on hand, one that will let you change your mind and switch all the getters to directRefs, and back to getters again, at will. Which of course you do, so go ahead. Lucky you. (do stick to the convention in the <Class> case though... ) > > Cheers > -Panu Viljamaa Cheers, -cstb |
cstb wrote:
> So the trace is > (self transformer) selector > --> (self class transformer) selector > --> ActualReceiver selector > What I'm proposing is to always access a global or class (for instance NeededClass below) with something like: self NeededClass --> (self whichClassToUse) NeededClass "POSSIBLY" --> (self class whichClassToUse) NeededClass "POSSIBLY" --> ActualReceiver NeededClass "POSSIBLY" The point being that the most important / valuable step is the first one. I don't go into detail of what *should* happen inside 'self NeededClass'. Using 'whichClassToUse' inside it may indeed the best solution, but I allow the situation and circumstance affect that decision. In effect I encapsulate this decision inside my (i.e. self's) method #NeededClass. In Smalltalk, the SystemDictionary 'Smalltalk' is the 'holder of globals'. In fact the compiler gets the classes from it - but with no regards to encapsulation. Therefore in many cases I've written: self NeededClass --> self Smalltalk NeededClass The above I think follows your pattern closely: Delegate to an object responsible for knowing the thing asked for, but do the delegation by accessing the delegate via a further message-send. Since 'Smalltalk' (The SystemDictionary) above is accessed via a method, it is easy to come up with the idea that each 'self' may in fact have their own SystemDictionary. Then it becomes only natural to make the small step of calling such objects 'namespaces' instead: self NeededClass --> self namespace NeededClass But as I said I find such indirection often *more than enough*, and would rather refactor my code to that form only when needed. Why? Looking at the last example, I still don't know which *actual* class gets returned, and figuring that out takes an extra level of effort. There's a fine balance between *forces* of minimizing dependencies, and maximizing readability. How to balance these forces naturally depends on the circumstances. - Panu Viljamaa |
In reply to this post by Chris Uppal-3
Chris Uppal wrote:
> The relevance is that since "my" classnames are hidden, and there is only the > one "global" identifier, all the actual classnames can be (and are) long and > descriptive without impacting clients of my code (if there were any). Ok. What I'm getting at is that there should be one "global" identifier *per programmer or project*. That would reduce the possibility of name conflicts even further. And perhaps this was your intention too. Regards -Panu Viljamaa That in > itself makes it highly unlikely that I/they will experience clashes. Also the > fact that all (just about) references to classnames from inside the module are > centralised in the 'Music' object means that changing them is extra specially > easy -- should the need ever arise. > > There is, of course, no way that I can write *my* code such that it reduces the > possibility of name clashes between two separate third parties. > > Well, not unless I go ahead and implement my "non-intrusive namespaces" > suggestion from elsewhere in this thread -- I'm getting increasingly tempted to > have a pop at it, it looks quite easy to do a bare-bones (little/no tools > support, global identifiers only, no selector namespaces) implementation. > > -- chris > > > |
In reply to this post by Dave Harris-3
Dave Harris wrote:
> > > > > In any case, asking the consumer to sort it all out means we can't > > > > > very well load classes dynamically, on an end-user's machine > > [...] > > I still don't see your point. > > The scenario I had in mind was when the choice of 3rd party packages to be > loaded was made by the end-user. As such it cannot be fully anticipated by > the programmer in advance, so the programmer cannot write a script. Right. Is that a scenario you consider important ? I suppose architectures like Java's servlet/servlet containers could use it. I'd have thought that that kind of situation would require better isolation between modules than just namespace protection. > > That's to say that almost *any* way of indicating which methods were > > intended for public consumption would work. > > I think that any solution has to deal with the full gamut of complexity, > including having a run-time presence (ie not just load-time), and will end > up being equivalent to selector namespaces in semantics. Perhaps it can be > done without special syntax, but I think having syntax reflect semantics > is often better. Yes, I think that the runtime support would end up being just about the same. The question is whether to package it as a language element, or as a tool. I think that this is a point we've disagreed on before, I prefer to avoid putting stuff into the language unless you *have* to. My main argument being that folding a tool into the language will loose more in flexibility than it gains in transparency. As an example, consider Java's protection/encapsulation mechanisms -- if I want something that's like "protected", but just a little-bit different, then I'm hosed. If the protection mechanisms had been exposed as tools (possibly with a little bit of syntactic sugar) then I'd be able to brew up my own protection level. Come to think of it, another example that's more relevant to this thread (albeit still in a Java context) is actually causing me problems in a design I'm mulling. In Java namespaces, protection, and classloaders all interact. I'm in a position where what I'd *like* to do is have a bunch of classes with very low encapsulation walls between them (the classes are machine generated and don't directly correspond to any object in the programmer's conceptual space -- they are low-level implementation artefacts). So what I'd *like* to do is put them all in the same namespace/protection domain (Java's so-called 'package access' or 'default access') and allow unrestricted access from within that domain. The problem is that they are created by different classloaders, and so they aren't (as far as the JVM knows) in the same package. So my only options are to allow "world" access to the innards of my generated classes, or to give up on the idea of having low barriers between them. I haven't yet decided what to do -- I don't care much for either alternative. I think the underlying problem here is that although Java does expose its namespaces in a way that I can (up to a point) manipulate by playing classloader games, it doesn't provide corresponding control over the semantics of protection levels. Of course, my other objection to language changes is that it forces namespaces into the foreground of programmer's attention -- where I don't think they would earn their keep. If all code has to be namespace aware, then not only does it mean more work for the poor programmer (me!), but it means that the external form of the code will loose compatibility with other Smalltalks -- which is where this discussion began... -- chris |
In reply to this post by Panu Viljamaa-5
panu
> Ok. What I'm getting at is that there should be > one "global" identifier *per programmer or project*. > > That would reduce the possibility of name conflicts > even further. And perhaps this was your intention too. Well, I was working in standard Smalltalk, so the names of the classes were still there in the global namespace. However I was attempting to program in a style that didn't make use of them. As I said, I quite liked the way the code worked out. But I wouldn't use it for every project -- two downsides being the unidiomatic code, and the tendency of the 'system' object to acquire (some of) the disadvantages of a God-class. -- chris |
In reply to this post by Panu Viljamaa-5
"panu" <panu@fcc.net_NOSPAM> wrote in message
news:[hidden email]... > Blair McGlashan wrote: > > > I'm afraid there is a downside, and it is incompatibility. There is no one > > standard namespace system, in fact they are all different, and often not > > just in the detail. ... > > There is a simple workaround for class-namespaces that > works in *every* Smalltalk (and in Java too). Before > complicating things further by adding explicit class- > namespace support to a language, consider using this > design pattern: [snip description of pattern] > This has the added benefit (over plain namespaces) > that you now *encapsulate* the information of which > actual object will be returned by #Transformer! Great and important benefit! > Using a method-call in this manner leads to more > cohesive, flexible, reusable code than accessing > a global directly (in several places). Remember > the Trick-of-63: Globals are BAD. Yes, but you can do even better. > The downside is that 'self Transformer' is slightly > longer than plain 'Transformer', but that's the > price you pay for better encapsulation, and for > keeping the language & code simple and compatible > with other dialects. Just put it in a class variable named 'Transformer' (same class where you would have put the #Transformer method) and get all the benefits without any of the downsides. Smalltalk in fact /does/ have a standard namespace system in the form of class variables (okay, it's broken in Squeak, but it works fine in Dolphin and the main other dialects). Cheers, Peter P.S. I'm trying to point out something that might be helpful. I hope to avoid coming across as an 'insufferable pedant' or some such :-)))). |
In reply to this post by Chris Uppal-3
[hidden email] (Chris Uppal) wrote (abridged):
> > The scenario I had in mind was when the choice of 3rd party packages > > to be loaded was made by the end-user. As such it cannot be fully > > anticipated by the programmer in advance, so the programmer cannot > > write a script. > > Right. Is that a scenario you consider important ? Not for me directly, but I'd hesitate to adopt a standard which ruled it out, and I'd hesitate to adopt a technical solution which could not be standardised (regardless of whether the political climate makes standardisation likely). > The question is whether to package it as a language element, or as a > tool. Normally I'd say new features should be a tool, or at most part of the library. I feel a bit differently about namespaces because I see them as being fundamental to OO. OO is about different objects both having their own definition of method #foo and the system making it all work. Preventing unwanted interference between modules that use the same names to mean different things is crucial to making software construction scale. What I've read of David Simmon's articles about selector namespaces in S# only reinforces this view. They seem so fundamental to the way the system works that they ought to be implemented at system level. Actually, I don't think you're necessarily disagreeing with this. I suspect the real question is whether there should be special language syntax. Whether we should have things like #namespace.selector supported as literals. I am fairly open about that. I don't feel qualified to answer. I suspect that a key feature will be the availability of unutterable namespaces. There's no point my having MyPrivateNamespace if it means other people can write #MyPrivateNamespace.selector as a literal selector. The only way you should be able to get hold of a selector from my namespace is by sending me a message - which I can reject if I don't like the look of you. > My main argument being that folding a tool into the language will > loose more in flexibility than it gains in transparency. > [...] > I think the underlying problem here is that although Java does > expose its namespaces in a way that I can (up to a point) manipulate > by playing classloader games, it doesn't provide corresponding control > over the semantics of protection levels. If you are saying we don't yet understand selector namespaces well enough to hard-wired them into the language, then I'm not qualified to comment. Certainly /I/ don't understand them well enough, but there are better qualified people out there who maybe do. But I sympathise with the sentiment. If, however, by "flexibility" you mean you want to be able support several different semantics for namespaces within a single image, then I am a lot less sympathetic. In any case, Smalltalk is quite a hackable language. Having something implemented at system level does not preclude being able to customise it. -- Dave Harris, Nottingham, UK |
In reply to this post by Panu Viljamaa-5
panu wrote:
> > cstb wrote: > > > So the trace is ^^^^^ Panu, I meant this to indicate that what followed (further down) was a trace, rather than source code; hoping you'd read it similar to tracing an algebra problem like this: 4 * x + 4 = 2 4 * x = -2 x = -1/2 > > (self transformer) selector > > --> (self class transformer) selector > > --> ActualReceiver selector > > but I think you took it as something else entirely. Sorry - poor description on my part. > What I'm proposing is to always access a global > or class (for instance NeededClass below) > with something like: > > self NeededClass > ...more steps snipped... > The point being that the most important / valuable > step is the first one. I don't go into detail > of what *should* happen inside 'self NeededClass'. We're talking past each other, I think. I'll be trying (below) to repair the disconnect, so others may want to take this as a yet-another-pedantic-bore warning, and bail now... ==== > Using 'whichClassToUse' inside it may indeed ^^^^^^^^^^^^^^^^^ This is a mis-interpretation, I think. Let's replace the mistaken word and keep going: > Using inside it may indeed be 'some specific code' > the best solution, but I allow the situation and > circumstance affect that decision. In effect I > encapsulate this decision inside my (i.e. self's) > method #NeededClass. Right - we're agreeing up to this point. > In Smalltalk, the SystemDictionary 'Smalltalk' is the > 'holder of globals'. In fact the compiler gets the > classes from it - but with no regards to encapsulation. Yes. > Therefore in many cases I've written: > > self NeededClass > --> self Smalltalk NeededClass > > The above I think follows your pattern closely: > Delegate to an object responsible for knowing > the thing asked for, but do the delegation by > accessing the delegate via a further message-send. No - although the *contents* of the pattern can be read that way, the *intent* of the pattern is something else, and the intent isn't carried through in your example. Delegate to an object responsible for knowing the thing asked for. Yes. Now an important distinction - if the thing being asked for is *not* a collaborating class, doing as you describe is fine; but - if the thing being asked for is a collaborating class, the pattern is: use (as a delegate) another class, which is either a) my own class or b) a superclass of my class. Such that you ... do the delegation by accessing the delegate via a further message send... *to myself*, with then an indirection to get from myself to the actual Delegate's method. If you use this pattern *all the time*, then you get the {very desireable} results I described in the previous post. Therefore, where our (separate) discussion of namespaces needed to refer to a collaborator, I injected the above pattern into the discussion, because I *always* use this when collaborators are involved, regardless of whatever else is going on. Perhaps unfortunately, the details of this pattern interfered with the description of the patterns we were actually discussing. ==== And here I'll admit that I don't know whether it is fair to refer to the above as a pattern, it might be an idiom, and hence off topic for half the distribution. I can't decide, so I left the distribution alone. ==== Now, quite apart from all the above, I'll add that your description below, motivating the idea for namespaces, is great. Thanks for including it. Cheers, -cstb {I suppose I should sign this one -yapb } ---- > Since 'Smalltalk' (The SystemDictionary) above is > accessed via a method, it is easy to come up with > the idea that each 'self' may in fact have their > own SystemDictionary. Then it becomes only natural > to make the small step of calling such objects > 'namespaces' instead: > > self NeededClass > --> self namespace NeededClasses. > > > - Panu Viljamaa |
Free forum by Nabble | Edit this page |