I haven't fully grokked the code changes in the syntax-control branch yet. However, I have read over the design notes in TODO, and pulled them out into a separate file, which I am attaching here. I have annotated with a number of open questions, and added a bullet point to document rationale, which is currently mostly a place-holder for a statement.
WRT my concerns about the syntax-control modifications: I have done some rooting around and have found a few libraries that are intended to set up a system for interactive use with a special readtable. These are things like expert system shells, etc. So at some point near the end of their system load, they will set *READTABLE* prior to finishing the load and dropping out for the user to deal with them. I can see that someone might not like this -- indeed, I'd rather there was a (START-FOO-SHELL) command instead. On the other hand, note that these are not really LIBRARIES; these are SYSTEMS. These are not intended to be slurped into something else: the programmer expects that his/her system will load, set up things for an interactive user, and then hand back control to the user through the REPL. Isn't the syntax control approach fundamentally incompatible with this? I don't think this is an especially tasty thing to do, but I'm also not convinced that it's ASDF's job to break arbitrary CL anti-patterns. Changing this behavior is likely to give very confusing bugs that won't be obvious to the poor user. On the other hand, I see files where there's something that sets the READTABLE obviously where what's intended is to simply set the readtable for the compiling and loading of this one file, and leaking that change is wrong. Note that a programmer who wants to be clean about this, in the current world, can set the readtable at the top of a file, and restore it at the bottom. If we take away the current behavior, the programmer who wants to set things up for the user is just completely out of luck. Or, maybe not: the very sophisticated ASDF user could add a PERFORM method on LOAD-OP on the interactive system. I think. I haven't grokked what's going on in syntax-control well enough. I am in a quandary about this. IMO the problem is a hole in the CL spec, which doesn't provide a good way to distinguish between two different intended uses for readtables. Before merging the syntax-control mods, I need to be convinced that it's appropriate for the ASDF community to force a solution to this problem on the CL community, instead of leaving the CL community to pick its way through the issue as it has to date.
* Syntax control: objective What is the problem that we are trying to fix? It seems like we are trying to fix uncontrolled, unintentional leaking of readtable side effects, without removing /intended/ leaking of readtable side effects. * Syntax Control: implement and document this plan 1. ASDF maintains an =asdf:*shared-readtable*=, which is the =*readtable*= object at the time it was loaded. [RPG: What is the intended function of the *shared-readtable* as distinct from the default readtable?] 2. This *shared-readtable* is subject to the current restrictions: [RPG: what do you mean by "current" in this sentence? I mean, in the current CL world, the readtable is a mess; there are few, if any restrictions. Is this a just a typo for "the following restrictions"?] A. no modifying any standard character, B. no two dependencies assigning different meaning to the same non-standard character. [RPG: what is a "dependency" in this context? Do you mean "no system should be loaded on top of systems that assign different meanings to a character in asdf:*shared-readtable*?] C. libraries need to document any change to the readtable [RPG: should "the readtable" be "asdf:*shared-readtable*"?] D. free software libraries will register these changes on the page on cliki. 3. Unhappily, there is no cheap way to enforce these restrictions, but that's no regression with respect to the current situation. 4. ASDF wraps any compile-op and load-source-op in this asdf:*shared-readtable* [RPG: to be painfully explicit: "ASDF binds =*READTABLE*= to =ASDF:*SHARED-READTABLE*= around any =PERFORM COMPILE-OP= and =PERFORM LOAD-SOURCE-OP="? Is that a correct reading?], but probably not =load-op=, to preserve combine-fasl linking semantics. 5. Systems that want to do crazier things with the readtable that may violate (2) must arrange to use their own private readtable, but can otherwise do it safely. It is an error (unhappily not enforceable) to modify the current readtable in these ways. [RPG: I'm not at all sure I know what "the readtable" refers to in the paragraph above. Is it "the current value of =*READTABLE*=," "the value of =ASDF:*SHARED-READTABLE*=," or something else?] 6A. ASDF binds =*readtable*= to the =*shared-readtable*= at the start of every system's compilation (and loading?), and around the entire =ASDF:OPERATE=, leaving the *readtable* unchanged at the end. [RPG: Please clarify -- I don't see how we can wrap around the entire =OPERATE= while at the same time /not/ doing loading as well as compilation. What's the precise scope of the binding of =*READTABLE*=?] This easily supports systems that "modify the current readtable data structure". However, that doesn't handle systems that "bind *readtable* to a new value", because the changes they make will shadow the changes that other systems following this style make and depend on. [RPG: We need to clarify the preceding sentence. In particular, given the way CL works today, we can't actually /bind/ =*READTABLE*= in a useful way: we always end up setting it. A simple example would help.] To allow such an idiom, we must also do the following: 6B- ASDF binds =*readtable*= to a proper "entry readtable" at the start of every system's compilation, and records an "exit readtable" at the end of the system's loading. [RPG: 6B seems to directly contradict 4.] 7. Maintain a partial order on these readtable objects, assuming that each system's exit readtable supersedes the entry readtable. The least readtable is the *shared-readtable*. It's enough to store for each new exit readtable, identified by the name of system that created it, the set of its inferior readtables, as a list or eq-hash-table, or an equal hash-table, with each readtable being identified by the name of the system that created it. 8. before a system is compiled or loaded, compute the maximum readtable of all the exit readtables of its dependencies. If this maximum is unique, then it will be the entry readtable of the system. If there is not a unique readtable that is more than all the other ones, that's an error, and we refuse to load the system. [RPG: I /think/ I follow this: the idea is to compute what the actual readtable dependencies are, as a means of ensuring repeatability, as build operations may be interleaved in different situations.] [RPG: Another point -- we aren't actually computing the maximum readtable as a readtable object, are we? Instead we are computing a dependency graph, right? And the nodes are readtable /designators/, rather than readtables, right?] 9. after a system is loaded, check its exit readtable, if it already exists, check that this doesn't create a cycle or issue an error. If the exit readtable doesn't already exist, add it to the set of all known exit readtables. 10. ASDF either a. binds the *readtable* to the *shared-readtable* around the entire asdf:operate, leaving the *readtable* unchanged at the end, or b. always side-effects the *readtable* to correspond to the exit readtable of the loaded system, or c. operate does the binding around thing, but load-system does the side-effect after it's done operate'ing. Does that strike you as complex? Because it is. That's the price of *safely* supporting this "systems can bind a new value to *readtable*" style. Unhappily some of the constraints are not enforceable (2A and 2B), but that's the very same as now. So my next question is: do you want to safely support these conventions? Do your systems modify the current *readtable* structure, or do they bind *readtable* to a new value? [RPG: So what is implemented in the syntax-control branch?] # Local Variables: # mode: org # End:
_______________________________________________ Asdf-devel mailing list Asdf-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/asdf-devel