Re: symbol resolution (was:EuCOM : Attn Matt : String Return Value)
- Posted by CChris <christian.cuvier at ag?icultu?e.gouv.fr> Oct 15, 2007
- 850 views
Matt Lewis wrote: > > CChris wrote: > > > > Matt Lewis wrote: > > > > > > > > > I agree that my solution doesn't really deal with the encapsulation issue. > > > That's not the point, and I don't believe that your solution really solves > > > the issues at hand. The point is to fix the problem of using multiple > > > libraries and having them conflict with each other. If two libraries > > > export the same symbols, you still have the same problem. > > > > > > > If your application includes two libs which export the same identifier, it > > has > > to explicitly choose one of them, using the current namespace system. At > > least, > > internal (ie global, but not interface) symbols won't be seen, just > > interface > > symbols. > > Yes, but what about those two libraries. One will have been included in > the main app after the other. Did the author use namespaces for everything > in his library? The first included library has polluted the namespace. > How does the second library manage to deconflict the symbols? > There are two ways around it: 1) As explained in my paper, write a wrapper include around say the first library, and filter the clashing symbol out from there:
-- app.exw include wrap_lib1.e -- managed inclusion of lib1.e include lib2.e -- more code here -- wrap_lib1.e -- define a package around the rogue lib package lib1_filtered = <comma separated list of allowed symbols from lib1> -- enforce it with package lib1_filtered -- now in protected area include lib1.e -- very complicated three lines
So, if lib1.e defines symbols that would clash either with identifiers in app.exw or in lib2.e('s subtree), they will be screened off and neither lib2.e nor app.exw will see them. wrap_lib1.e is to be written by the application coder, since the list of clashing symbols depends on the other third party libs and the app.exw code. 2/ If only a couple symbols cause trouble, which is expected to be the most frequent case, it is even simpler to do this:
-- app.exw include lib1.e restrict clashing_symbol_1 from lib1.e to lib1.e --... restrict clashing_symbol_N from lib1.e to lib1.e include lib2.e -- more code here
with exactly the same effect. If the symbols come from lib1.e's subtree, then solution 1/ is in order. > > > What happens when the library maintainer makes some changes, and the > > > packaging directives don't keep up? > > > > > > > The maintainer usually tests his lib, and specially the new functionalities, > > and something won't work right, which he should fix before shipping. > > > > If the directives are in some custom wrapper you wrote, then it is your call > > to keep the wrapper up to date, since you wrote it. Or to ship an update for > > your application, so that an user can use the new version of the lib. > > > > If the packaging uses a negative list, ie a list of internal symbols, then > > adding > > more exported symbols requires no update at all. > > In a perfect world, this would be done. And I agree that this isn't, in > and of itself, a deal breaker. I am saying that it's creating another > way to create bugs. How would the author know that he'd missed something? > That his library causes problems with some other piece of code that hasn't > even been written yet? He wouldn't. By properly marking internal symbols as such, he'd eliminate their clashing with anything, so only interface symbols may still cause problems. If someone uses another library with same interface, then see above. > > The end result is that the users of the library are going to have to do > extra work (by effectively editing the code of the library) to use this > library, which is exactly what I'm trying to avoid. > Definitely not true. As the examples above show, the system is designed to _completely eliminate_ any third party code editing. It also enables one to deal with legacy code (ie without internal or exported), using export lists in wrapper includes. > A negative list may reduce the chances of having to go in and edit, but > it does not solve the problem. It does, however drive up the complexity > of the code. > Not really. SymTab has two more fields, one of them being the initial package and the other the current package. If a symbol is *exported*, initial package is -1; if *internal*, it is current_package; if *global*, the relevant package list is looked up so as to determine whether this is internal or exported. Finally, keyfind() checks from the current package field if som global is visible. For example, contrary to your implementation, no change of file structure in the front end is required in order to include it as a library. Just a wrapper as a stopgap, or marking all current global symbols as internal if they are not to be seen outside > > > > > Also, your solution seems to me to be overly complex, and difficult to > > > maintain. When we get to encapsulation, I think I'd prefer something > > > along the lines of an import vs include, where the globals "imported" > > > don't go beyond the file that imported them. This way, if you need to > > > keep stuff hidden, just import it. If you want to expose things, either > > > put it in the main include, or use the standard include directive. > > > > > > It's possible that I just don't understand your proposal sufficiently. > > > Please submit a modified set of files to demonstrate how you'd modify > > > v3.1 to handle these files. The benefit of my proposal is that there is > > > absolutely no new syntax, and it does it in an intuitively straightforward > > > manner. > > > > > > > Huh? It does work for some obvious cases, but explicitly inluding a parent > > file, > > for example, is far from anything I'd call "intuitive or straightforward". > > This really baffles me. You have a file which uses symbols in another file. > If that other file is not present, then it won't work. You're saying that > it's unintuitive to include that file with the symbols you depend upon? > Since the identifier defined in the parent is already in the known symbol space, it is counter intuitive to add it again, yes. The only advantage I see in your scheme is the dependency being made explicit. Otherwise, it's more typing for less functionality, because then all symbols from parent will become viible from the included file, won't they? If they don't, read "same functionality". > > I'll have to post the files indeed. As I noted earlier, this may take some > > time > > because of RL fiercely catching up these days. But this is the way to go. > > Also, > > I didn't try adjusting the runtime lookup functions accordingly yet. > > > > > I'm not really interested (in this discussion) to hear about how your > > > solution encapsulates symbols. I'm interested in how we deal with > > > multiple files that expose duplicate symbols, whether the original > > > author wants them to be exposed or just used internally. Accept that > > > the symbols are exposed to the program. > > > > We obviously have different approaches. > > Well, if you're honestly trying to solve the namespace/third party conflict > problem then I'd agree with you, and I'd go farther to say that your > approach is deeply flawed. > I am trying to solve several related issues around name clashing and scope in one sweep, rather than applying yet another Band-Aid. So This is why my solution brings both encapsulation, overloading and name clash prevention in one consistent "package". The changes of syntax are: * 2 new scope modifiers, *internal* and *exported*, which are mutually exclusive with *global* and make the intent of the symbol known from just reading the code; * 2 new with/without directive parameter: + *with package <pkg>*/*without package* pushes a package layer onto the package stack; + *with previous_package* pops this stack. * 2 new top level directives: + *package <pkg> [[!]=<symbol list>]* defines which globals are exported/internal + *restrict <sym> from <id_def> to <new_scope>* changes the scope of an identifier. As explained, people who write multifile libs or apps that use several (multifile) libs will need or use some of the new syntax. Hardly anyone else is impacted. > > > It seems that your method puts a larger burden onto the programmer to > > > resolve conflicts. My goal is to take what's already there (all > > > those include statements) and to make full use of the information that > > > they impart. > > > > The only burden is to disambiguate between interface and non interface > > symbols. > > It is not a new task for programmer, since the docs he wrote usually do this > > already. > > You still haven't answered the main issue here. How does this solve two > third party library conflicts? I'll admit that I simply may not understand > your solution well enough, and maybe your examples will clear this up, > but you seem to be avoiding the question by saying, effectively, that > your solution reduces the number of global symbols, so probabilistically, > the chance of a conflict is reduced. > Of course it does. As the code above shows, it also addressesthe clashes between interface symbols. > I agree with you on that point. But your solution doesn't solve, AFAICT, > the conflicts themselves. So I'll use your terminology: > > How would your approach resolve conflicts between two interface symbols > conflicting in two third party libraries. The conflict exists because > the libraries (not just user code) use those interface symbols. > Therefore, simply having a program like: > }}} <eucode> > -- myapp.ex > include libMatt.e > include libCChris.e > </eucode> {{{ > ...causes an error somewhere inside of libCChris.e, because one of its > interface symbols conflicts with an interface symbol in libMatt.e. > > What would we need to do to make sure that this situation doesn't occur. > And what tools does the library programmer have to help him? > If two interface symbols collide, I think the examples above show exactly what to do from the _application writer's_ end. If a non interface symbol clashes with anything, then: 1/ The application writer can screen it off using the same method; 2/ Later, the library writer may mark interface symbols as *internal*, or define a package with either an export or exclude list, as s/he sees fit, and release a better behaved library. The wrapper will still work, but won't be useful then. This ensures immunity to change in library versions. > Matt Well, it looks like my paper is completely not understandable; however, I don't know what to do about it, because I had tried to make it as precise and detailed as I could figure out. Need some hints there. CChris