As Henrik wrote - there are other questions to tackle. It would be nice if you all reacted to the "minimal meta card" I talked about for example. :-) I am still "thinking" about the cataloging problem. It's a bit tricky to get something simple and still scalable.
But... that was not the thing I wanted to say. The issue with "imports" should be rather small I think because hopefully Squeak will "auto import" a module during compilation - at least if there is only one module active that does define that name. Henrik?
Ok, why don't I test it - so I did. I made a class with a method referring to Transcript. Compilation went fine and I guess that because Modules are still weak it even worked to run it without any neighbor modules. So ok, I need to do it explicitly, I ran the "self deepDeclareExternalRefs." from the explorer-thingy and then BAM, it added two neighbors:
#(Squeak Language Core)* #(Squeak Language Collections)*)
I am not sure why it didn't go all the way down to Streams... Even adding a reference to ReadStream didn't make it go there. It actually seems that these two modules are always neighbors - even with an empty method!
How come Henrik? I tried referencing another of my own classes and that got discovered correctly.
regards, Göran
goran.hultgren@bluefish.se wrote:
without any neighbor modules. So ok, I need to do it explicitly, I ran the "self deepDeclareExternalRefs." from the explorer-thingy and then BAM, it added two neighbors:
#(Squeak Language Core)* #(Squeak Language Collections)*)
I am not sure why it didn't go all the way down to Streams... Even adding a reference to ReadStream didn't make it go there. It actually seems that these two modules are always neighbors - even with an empty method!
The modules Language Core and Language Collections import all their submodules, including ReadStream.
hopefully Squeak will "auto import" a module during compilation - at least if there is only one module active that does define that name. Henrik?
Right. This is what deepDeclareExternalRefs does. But automatic declaration is not really an option, your module dependencies really describe the "organizational logic" of your code, which isn't evident from the names you use.
For example, if your module uses Balloon3D heavily, the auto-declarer will add, say, dependencies on five or more submodules of Balloon3D instead of a single one to the Balloon3D module, which would be the logically right thing to do. (Balloon3D then ought to import its submodules so you only need to declare a single dependency on that module.)
An auto-declarer can never discover that this is the "correct" higher-level logic behind your code, because sometimes you may want to import exactly two of the B3D submodules instead of all of B3D or whatever.
- Imports are made on module level. We already have that - the neighbor
modules. I think. 2. If you type a direct reference in the code it would generate an automatic neighbor module reference on compile. It would of course barf if that module is not loaded (it doesn't have to be active, right?). 3. If you type a non direct reference like "EllipseMorph" then I would like it to:
- If there is already ONE and ONLY ONE neighbor module exporting
EllipseMorph then do nothing. All is fine. 2. If there are two or more neighbor modules exporting EllipseMorph then barf and ask user to make a direct reference using whatever syntactic means there are for that. :-) 3. If there are no neighbor modules exporting EllipseMorph, find it among all loaded modules and if there is ONLY ONE - add that module as a neighbor. Ask user for confirmation. This could be a Preference. 4. If there are more than one loaded module exporting EllipseMorph, ask which one should be added as a neighbor.
This sounds like a very good solution.
Now, as you noted, there still is the odd case when you need to specify in your code exaclty what module to pick a name from, e.g. where there is a name conflict (perhaps Component is more likely to have a conflict than EllipseMorph though!)
Like David S. noted (and Les did last fall), giving the full path inside your code is brittle. So I fully agree,
ellipse := Squeak Morphic Core Basic EllipseMorph new.
is not a great idea. That is why you can use aliases for external modules, e.g. you'd declare that your module depends on #(Squeak Morphic), and that this module should have the alias Morphic inside your module.
so in the dependencies (the "interface" of the module):
... externalModule: #(Squeak Morphic) alias: #Morphic ...
and in your code,
morph _ Morphic Component new
to distinguish it from the Component class in the super-meta-reflective programming code you also depend on:
... externalModule: #(Project FancyMetaProgramming) alias: #MetaSystem ...
model _ MetaSystem Component new
I think this is acceptable, even probably preferrable to other solutions IMHO.
On the same note, using prefixing, i.e. always using Morphic Component instead of just Component, probably leads to less brittle code, since you are always explicit and clear about where you are taking a name from. Just "blindly" using imported names from all over can lead to really confusing bugs.
If people don't want to have to declare aliases all the time, then the name of the last module in the path could be allowed as a default, ie. #(Squeak Morphic) would allow Morphic as an alias by default, but perhaps that is not worth the potential confusion.
But it sounded as Stephen wa talking about having "the old" references still point to the "old" name but the new ones (after having added the extra neighbor) point to the new name. Uahh! That sounds SCARY to me. How would I know what it points at by reading the code? Perhaps I misunderstood.
It would also cause recompilation to fail, so it wouldn't work in practice.
Unfortunately, an implicit reference will not work when loading the module into a fresh image (how would we know what module to bind it to? And, we don't want to prompt the user at load time). Implicitly binding based on the order of the modules would be tricky and obscure as well.
Yes, you couldn't be allowed a choice between different bindings for the same name, you'd always have to use the first one given by the order of your imports. Otherwise loading or recomp. would fail. Or each Squeaker loading your module would have to specify which binding you intended your code to have. ;-)
Lex Spoon wrote:
Modules @ #Morphic @ #Core @ #Basic @ #EllipseMorph
Now you can look up #@ and see what is happening, where before you had to lookup up #doesNotUnderstand:.
Here, it would translate to
model _ (Morphic @ #Component) new
which I think would be acceptable (but one must remember to use parentheses for this one). But beginners are likely to be confused by the # here, since they already are puzzled by having to use #SubclassName when creating new classes. So I don't think there is a "perfect" solution to this.
Stephen Pair wrote:
Regarding the issue of importing a new module that has a duplicate export of a symbol that's already being used...maybe the solution to this problem is to enhance what the compiler is producing. Rather than compile in references directly to an association, maybe we should compile in a reference to something a little more sophisticated...if we change the VM such that the #value method is actually sent (rather than make an assumption about having an association), this should be an easy thing to achieve (and it's arguably the right thing to do regardless).
This is propbably what Dan had in mind with the uppercase message mechanism. "Morphic Component" will actually send a message to the value of the Morphic binding, causing this lookup, like you suggest (if I understoood you correctly). And this with no special machinery. No recompilation needed if the binding of the alias Morphic changes.
Also, someone suggested that we automatically would compile in methods that would return the variable value, instead of using doesNotUnderstand: like now.
On another note, regarding the upper case convention, what happens for lowercase modules names? Like "People svp"? Would we need to make the people modules upppercase? Like "People Svp" or "People SVP"?
Note that this is just a special convention for accessing names defined in modules (which may be their submodules, or globals, but typically classes). So the message selector is identical to the accessed name. So if you would deviously force your module to define the global "myGlobal" (non-uppercased) then "YourModule myGlobal" would be the message to access it.
I actually just encountered such a situation when trying to load the ModuleTool...it requested version 0.0003 of the module code and wouldn't load because I had 0.0004...even though the tool seems to work fine when I modified the def file to require 0.0004.
Yeah, it is still waiting for someone to implement a real versioning system. <hint> But the warning dialog could be better I think.
Actually this is a meta-level check, to ensure that the module code will be able to understand the definition format used in the file. Any refinements to the very crude current check are warmly welcome.
Henrik
Well, whatever, perhaps I am "out bicycling" as we say in Sweden. :-)
Note to non-Swedish speakers: Göran's Swenglish is hilariously funny if you know the expression in question!
On Mon, 25 Feb 2002, Henrik Gedenryd wrote:
That is why you can use aliases for external modules, e.g. you'd declare that your module depends on #(Squeak Morphic), and that this module should have the alias Morphic inside your module.
so in the dependencies (the "interface" of the module):
... externalModule: #(Squeak Morphic) alias: #Morphic ...
and in your code,
morph _ Morphic Component new
to distinguish it from the Component class in the super-meta-reflective programming code you also depend on:
... externalModule: #(Project FancyMetaProgramming) alias: #MetaSystem
...
model _ MetaSystem Component new
I think this is acceptable, even probably preferrable to other solutions IMHO.
On the same note, using prefixing, i.e. always using Morphic Component instead of just Component, probably leads to less brittle code, since you are always explicit and clear about where you are taking a name from. Just "blindly" using imported names from all over can lead to really confusing bugs.
If people don't want to have to declare aliases all the time, then the name of the last module in the path could be allowed as a default, ie. #(Squeak Morphic) would allow Morphic as an alias by default, but perhaps that is not worth the potential confusion.
Well, it would allow for backwards-compatibility. There's a lot of code out there, even good tutorials that should not have to be rewritten. It should suffice to tell the newbies to "import the Morphic module first" and all is fine.
-- Bert
Henrik Gedenryd wrote:
goran.hultgren@bluefish.se wrote:
hopefully Squeak will "auto import" a module during compilation - at least if there is only one module active that does define that name. Henrik?
Right. This is what deepDeclareExternalRefs does. But automatic declaration is not really an option, your module dependencies really describe the "organizational logic" of your code, which isn't evident from the names you use.
For example, if your module uses Balloon3D heavily, the auto-declarer will add, say, dependencies on five or more submodules of Balloon3D instead of a single one to the Balloon3D module, which would be the logically right thing to do. (Balloon3D then ought to import its submodules so you only need to declare a single dependency on that module.)
An auto-declarer can never discover that this is the "correct" higher-level logic behind your code, because sometimes you may want to import exactly two of the B3D submodules instead of all of B3D or whatever.
Auto-declaration (auto-import) of required modules would still be nice to have as an option, if not as the default. (Actually I don't think it would be *that* bad as the default, either.)
I assume that things would still work if you completely relied on auto-declaration? The declarations would just be sloppier, as you say... you might have a group of submodules declared when you logically should just declare a dependency on the whole module.
Auto-declaration might be workable if you had a module browsing tool with a good UI, which made it obvious when you had this sort of sloppiness in your declarations, and made it easy to clean things up.
Like David S. noted (and Les did last fall), giving the full path inside your code is brittle. So I fully agree,
ellipse := Squeak Morphic Core Basic EllipseMorph new.
is not a great idea. That is why you can use aliases for external modules, e.g. you'd declare that your module depends on #(Squeak Morphic), and that this module should have the alias Morphic inside your module.
so in the dependencies (the "interface" of the module):
... externalModule: #(Squeak Morphic) alias: #Morphic ...
and in your code,
morph _ Morphic Component new
to distinguish it from the Component class in the super-meta-reflective programming code you also depend on:
... externalModule: #(Project FancyMetaProgramming) alias: #MetaSystem
...
model _ MetaSystem Component new
I think this is acceptable, even probably preferrable to other solutions IMHO.
I agree that this sounds better than using full paths. If this is done, then the debate about exactly how to specify full paths becomes less important.
On the same note, using prefixing, i.e. always using Morphic Component instead of just Component, probably leads to less brittle code, since you are always explicit and clear about where you are taking a name from. Just "blindly" using imported names from all over can lead to really confusing bugs.
Hmm, this is a close call... I'd say comparing prefixing (with aliasing) versus no prefixing (blindly using imported names), neither would be all that brittle. Using no prefixing would require that the tools do more work, e.g. to notify you when you've imported/declared a new module which happens to import a duplicate name which your code references, which you now must make explicit. (Making the appropriate references explicit could then be done automatically at the press of a button, as Stephen suggested.)
I guess that's the main difference between the two approaches:
You can either do prefixing, which requires that you set up aliases and always include a module prefix before every classname (bad), but then you don't have to worry about having a duplicates problem when you import/declare new modules (good).
Or, you can blindly use imported names, and not have to worry about any aliases or adding prefixes before classnames (good), but you might have a problem when importing a new module (bad). (But then, if this problem is handled relatively automatically when it occurs, is it really that much of a problem? I can't think of any "confusing bugs" that might happen that wouldn't be solved by making the appropriate references explicit at the right time, although I may be missing something.)
Hm, I admit that prefixing could be helpful for readability in certain cases, such as with something like "Component", which might be too vague on its own, and might appear in a few well-known modules... in that case if you use "Morphic Component" you're identifying it as, well, the Morphic Component, not some other Component.
If people don't want to have to declare aliases all the time, then the name of the last module in the path could be allowed as a default, ie. #(Squeak Morphic) would allow Morphic as an alias by default, but perhaps that is not worth the potential confusion.
Yeah, that might be a bit tricky.
- Doug Way dway@riskmetrics.com
Is it settled then? Let's at least allow aliases for external modules for now and change the module def file to accomodate that. Allowing module substitutions and config specs can come later. I'd prefer it if aliases were required when importing a module (then people would be more likely to use the alias for explicit references rather than the full module path). I think my personal coding practice would be to use explicit references through aliases in any reference to an external name...it just seems like the best thing to do and "Morphic Component" is not ugly at all.
So, I'm studying the code and I see that ModuleReference has a method called #alias. Which is exactly where I would have put a method to look up the alias for a neighbor module in the definedNames. What is the indentended use for this alias?
- Stephen
-----Original Message----- From: squeak-dev-admin@lists.squeakfoundation.org [mailto:squeak-dev-admin@lists.squeakfoundation.org] On Behalf Of Doug Way Sent: Wednesday, February 27, 2002 12:57 AM To: squeak-dev@lists.squeakfoundation.org Subject: Re: [Modules] Upper case message names for accessing modules
Henrik Gedenryd wrote:
goran.hultgren@bluefish.se wrote:
hopefully Squeak will "auto import" a module during compilation - at least if there is only one module active that does define that name. Henrik?
Right. This is what deepDeclareExternalRefs does. But automatic declaration is not really an option, your module
dependencies really
describe the "organizational logic" of your code, which
isn't evident
from the names you use.
For example, if your module uses Balloon3D heavily, the
auto-declarer
will add, say, dependencies on five or more submodules of Balloon3D instead of a single one to the Balloon3D module, which would be the logically right thing to do. (Balloon3D then ought to import its submodules so you only need to declare a single dependency on that module.)
An auto-declarer can never discover that this is the "correct" higher-level logic behind your code, because sometimes you
may want to
import exactly two of the B3D submodules instead of all of B3D or whatever.
Auto-declaration (auto-import) of required modules would still be nice to have as an option, if not as the default. (Actually I don't think it would be *that* bad as the default, either.)
I assume that things would still work if you completely relied on auto-declaration? The declarations would just be sloppier, as you say... you might have a group of submodules declared when you logically should just declare a dependency on the whole module.
Auto-declaration might be workable if you had a module browsing tool with a good UI, which made it obvious when you had this sort of sloppiness in your declarations, and made it easy to clean things up.
Like David S. noted (and Les did last fall), giving the full path inside your code is brittle. So I fully agree,
ellipse := Squeak Morphic Core Basic EllipseMorph new.
is not a great idea. That is why you can use aliases for external modules, e.g. you'd declare that your module depends on #(Squeak Morphic), and that this module should have the alias Morphic inside your module.
so in the dependencies (the "interface" of the module):
... externalModule: #(Squeak Morphic) alias: #Morphic ...
and in your code,
morph _ Morphic Component new
to distinguish it from the Component class in the super-meta-reflective programming code you also depend on:
... externalModule: #(Project FancyMetaProgramming) alias:
#MetaSystem ...
model _ MetaSystem Component new
I think this is acceptable, even probably preferrable to other solutions IMHO.
I agree that this sounds better than using full paths. If this is done, then the debate about exactly how to specify full paths becomes less important.
On the same note, using prefixing, i.e. always using
Morphic Component
instead of just Component, probably leads to less brittle
code, since
you are always explicit and clear about where you are taking a name from. Just "blindly" using imported names from all over can lead to really confusing bugs.
Hmm, this is a close call... I'd say comparing prefixing (with aliasing) versus no prefixing (blindly using imported names), neither would be all that brittle. Using no prefixing would require that the tools do more work, e.g. to notify you when you've imported/declared a new module which happens to import a duplicate name which your code references, which you now must make explicit. (Making the appropriate references explicit could then be done automatically at the press of a button, as Stephen suggested.)
I guess that's the main difference between the two approaches:
You can either do prefixing, which requires that you set up aliases and always include a module prefix before every classname (bad), but then you don't have to worry about having a duplicates problem when you import/declare new modules (good).
Or, you can blindly use imported names, and not have to worry about any aliases or adding prefixes before classnames (good), but you might have a problem when importing a new module (bad). (But then, if this problem is handled relatively automatically when it occurs, is it really that much of a problem? I can't think of any "confusing bugs" that might happen that wouldn't be solved by making the appropriate references explicit at the right time, although I may be missing something.)
Hm, I admit that prefixing could be helpful for readability in certain cases, such as with something like "Component", which might be too vague on its own, and might appear in a few well-known modules... in that case if you use "Morphic Component" you're identifying it as, well, the Morphic Component, not some other Component.
If people don't want to have to declare aliases all the
time, then the
name of the last module in the path could be allowed as a
default, ie.
#(Squeak Morphic) would allow Morphic as an alias by default, but
perhaps that is not
worth the potential confusion.
Yeah, that might be a bit tricky.
- Doug Way dway@riskmetrics.com
Stephen Pair wrote:
Is it settled then? Let's at least allow aliases for external modules for now and change the module def file to accomodate that. Allowing
So, I'm studying the code and I see that ModuleReference has a method called #alias. Which is exactly where I would have put a method to look up the alias for a neighbor module in the definedNames. What is the indentended use for this alias?
As you found, the code already allows for aliases, and the module def file supports it already too.
goran.hultgren@bluefish.se wrote:
I would like to add support for the "minimal module metainfo" I was talking about earlier. I looked at the Annotations stuff but as I see it, these things does not get written to the external representation of the module.
Henrik - should/could we add this to the definition file or should we put it somewhere else, perhaps in a third, "noncompulsory" file? Was the annotations only meant to live in the image?
And since noone reacted on my list of fields I will go for what I posted. :-)
I think we can keep it in the def file for now, as in "keep it simple". I posted a few comments about some fields being redundant, otherwise the list was fine IMO.
Henrik
Henrik Gedenryd:
As you found, the code already allows for aliases, and the module def file supports it already too.
When you say "allows" for aliases, do you mean that external modules can be given aliases right now...and those aliases can be used when referring to a module? Or, are you saying that this need was anticipated, allowed for, but not fully implemented?
If it's implemented, a description of how to use it would be a nice addition to the modules page on the swiki.
- Stephen
Stephen Pair wrote:
When you say "allows" for aliases, do you mean that external modules can be given aliases right now...and those aliases can be used when referring to a module? Or, are you saying that this need was anticipated, allowed for, but not fully implemented?
You're right, it should work but there's a bug that prevents it from doing that right now.
If it's implemented, a description of how to use it would be a nice addition to the modules page on the swiki.
Ok, what should the name of the page be that would lead people to this information? (I'm homeblind.)
Henrik
Ok, what should the name of the page be that would lead people to this information? (I'm homeblind.)
Henrik
How about "Using aliases to reference external modules"? As long it is linked from the main Modules page (http://minnow.cc.gatech.edu/squeak/modules) people should be able to find it easy enough.
- Stephen
squeak-dev@lists.squeakfoundation.org