From mira@ccs.neu.edu Wed Jan 21 19:42:12 1998 Subject: Re: more integration To: dem@ccs.neu.edu Date: Wed, 21 Jan 1998 19:42:08 -0500 (EST) Hi Doug and Karl: in the following you will find my notes on Karl's mail yesterday and Doug's comments on it. It turned out to be a discussion among us three - that's why the head as a mail to Doug and Karl. However, I am sending it to "dem" in order not to exclude others from the discussion. Hope not bothering you with the long mail. -- Mira --------- cut here -------- Karl Lieberherr writes: > The JOURNALIZER pattern is described by an adjuster as follows: > > Adjuster JOURNALIZER (Strategy s = > {-> {Class1 Class2} Journal}) { at Class1 { > void event1() { > do s { // omitted during > at s.target { > when-visiting {host.event1();}}} > // maybe we can use some syntactic sugar here > // do s is a statement added to the OO language > next(); > } > void event2(Par p) { > do s { //ommitted during > at s.target { > when-visiting {host.event2(p);}}} > next(); > } > at Class2 { ... } > } > at Journal { > event1() { mystructure.register("Class1.event1" ); } > event2(Par p) { mystructure.register("Class1.event2", p); } > } > } Doug Orleans writtes: >I'm having trouble figuring out what this syntax means. Can you >suplpy the Java code that this would be translated into? Also, a >better indentation would help, as would lining up the braces... I'm also having problems with the Karl's syntax. I think it is heavy and contains redudancies. Let me rewrite the code and explain the idea behind it based on my understanding and than "negotiate" with Karl. The pattern we have here is as follows: "any time event1 and event2 are invoked on an object of Class1 (as well as certain other methods on objects of Class2 which are omitted above) messages with the same name are invoked on an instance of Journal that is part of the structure of Class1's instance on which event1 and event2 are being invoked. In other words, invokations of event1 and event2 on Class1 are registered in objects of Journal" Well, this is my intuition about the meaning of the code, Karl has written above. Karl could give the original description. Anyway, the collaboration between instances of Class1 and Journal via the path between Class1 instances and Journal instances is central for the behavior encoded by this pattern. The idea of modeling this pattern by means of adjusters parametrized by strategies is to make explicit the fact that responsibility is passed through the path mentioned above - in the strategy. I would have written the code as follows: Adjuster JOURNALIZER (Strategy s = {-> {Class1 Class2} Journal}) { Class1{ void event1() { before (@ // ... doSomethingBefore1 .. @) } void event2(Par p) { before (@ // ... doSomethingBefore2 .. @) after (@ // ... doSomethingAfter2 .. @) } } Class2 { ... } Journal { event1() { mystructure.register("Class1.event1" ); } event2(Par p) { mystructure.register("Class1.event2", p); } } } Assuming the following class graph: Class graph: Class1 = ... InfoManagement. InfoManagement = ... Journal. Journal = // ... whatever the generated java code would look like: Class1 { InfoManager admin; void event1() { // ... doSomethingBefore1 ... admin.event1(); } void event2() { // ... doSomethingBefore2 ... admin.event2(); // ... doSomethingAfter2 .. } InfoManagement { Journal journal; void event1() { journal.event1(); } ... void event1() { journal.event1(); } } Journal { event1() { mystructure.register("Class1.event1" ); } event2(Par p) { mystructure.register("Class1.event2", p); } } } Note: 1- I don't use "at". I definitely agree with Doug in the following: Doug Orleans writtes: >I think this is a good extension, and gives us a way to modularize >methods across classes. A minor syntax change would allow us to be >backwards compatible with the way Demeter/Java is now: remove the "at" >keyword (it seems superfluous), and assume that anything outside of an >adjuster is in some "default adjuster", similar to the "default 2- Code like the following found in Karl's "program" are omitted: KL> do s { //ommitted during KL> at s.target { KL> when-visiting {host.event2(p);}}} I think this is redundant. Since, the strategy is specified as a parameter of the whole adjuster, what has to be done when at target (= the class valued variable Journal) is already encoded by the code for event1 and event2 in Journal. 3- I use "before" and "after", agreeing with Doug: Doug Orleans writtes: >Again, I think we should keep the "before" and "after" keywords, instead of next -- however, for the case when "next()" denotes the code that performs the traversal. But, I am not sure about the correctness of the following remark by Doug: Doug Orleans writtes: > KL> void insert (EleType el) {next.insert(el); count++;} > KL> void erase (Node node) {next.erase(el); count--;} > >Again, I think we should keep the "before" and "after" keywords, in >which the call to next is implicit. Also, it might be better to have in the context he does it. In Karl's piece of code referred to by Doug above, "next" plays the role of "super". In the concrete scenario, it means the implementation of insert, resp. erase, in TIMESTAMP, which SIZEOF modifies, or refines, or uses, (... Karl uses "uses" but I am not quite happy with any of the above names) KL> modify by KL> SIZEOF_Visitor uses KL> TIMESTAMP_Visitor uses KL> BINTREE_Visitor Although "next" plays the role of "super", we don't call it "super" because of two reasons: a) to emphasize that layers of classes are being connected, i.e. that the super is not a class but rather a collection of classes. b) the origin is in Rondo, where they actually have differentsemantics: super denotes the static superclass of the class an object is created as the instace of, which next denotes the most specific dynamic variation performed on the behavior of the object. I would answer in a similar way, the following remark by Doug: Doug Orleans writtes: >the call to next be like the current around methods, i.e. a thunk >object which has only one method, apply(). Then the user won't have >to worry about the name of the method, or the arguments. I don't see how around methods would be used in this context. I would think about using them instead of next calls when next calls refer to the traversal code. But, still ... I kind of was not confortable with them as a novice in AP. They seem not very intuitive to me ... While with next calls, I can avoid continuing a subtraversal by simly putting the next call within an if-statement. This seems natural to me and does not require me as a programmer to learn a new (non Java) construct and remember its semantics. But, that might be a matter of taste. So, let discuss about that. --- SUMMARY --- At this point let me stop talking about details and return to a more abstract description of what we are talking about with those adjusters. Well, Karl and Doug already talk about that: KL> Adjusters allow us to talk about coordinated class refinement: KL> What we are trying to do is to integrate a bunch of useful ideas KL> into the Demeter/Java world: Mezini's Rondo ideas, Batory's KL> mixin layers, CLOS before and after and around methods and KL> Holland's contracts. All those works have something to do with modifying KL> groups of classes and that is also the main theme in the current KL> Demeter/Java. DO> I think this is a good extension, and gives us a way to modularize DO> methods across classes. I tend to see it as an alternative to using subclass-based frameworks (or white box frameworks) for constructing reusable software (reusable designs). The hope I have, is to show that adjusters as the building blocks for constructing reusable software would have two advantages compared to white box frameworks: - they are structure-shy, which white-box framework aren't; - although the core of frameworks consists of the collaboration patterns between classes in the framework, those are not explicit. They are however very important and very often constrains should be put on extensions (instantiations) of the framework to maintain them. A couple of works (started with Holland's contracts and including my own work presented at the last OOPSLA) are talking about providing tools on top of PL's responsible with "guarding" the extension of application frameworks. On the contrary, with the strategies of AP, by having them as parameters of an adjuster, the collaboration is made explicit - it is directly accessible for the extension programmer and it is maintained automatically, when inheriting from adjusters. Thus, it is no way to "break" the design structure of the framework. I believe that Ralph Johnson means more or less the same problems when he talks about "Problems with Frameworks" in a recent paper of him in a recent issue of "Communications of ACM". Here is a paragraph from the paper: ----- by R. Johnson ---- Current PLs are good at describing the static interface of an object. but not its dynamic interface. Because frameworks are described with PL's, it is hard for developpers to learn the collaborative patterns of a framework by reading it. Instead, they depend on other documentation and talking to experts. Patterns are one approach to improving the documentation. Another approach is to describe the constraints and interactions between components formally, such as with contracts [Holland et al.]. But since part of the strength of frameworks is the fact that the framework is expressed in code, it might be better to improve OOPLs so that they can express patterns of collaboration more clearly. ---- end of reference to Johnson -------- Unfortunatelly, Ralph does not say any word about what he means by "dynamic interface" of an object. I have the following understanding of some of the main terms he uses (based on the context): static interface == the set of methods defined on an object dynamic interface == collaborative patterns encoded in the behavior of an object, i.e. the set of paths through which responsibilities flow during run-time (the protocol?) If this understanding is correct, then the above paragraph is a perfect expression of what I wanted to say in the part of this mail talking about adjusters vs. application frameworks. Anyway, I will send an email to Ralph in order to be sure I have a correct understanding of what he is saying. To conclude, the idea is to make use of the technology which exists in AP (see below) in the context descussed above. KL> We already have adjusters in Demeter/Java: KL> KL> C { KL> int f() to Z (V); KL> } KL> KL> is an adjustment which extends only class C with f. There are several issues here: - more sophisticated examples are needed - granularity: + does an adjuster stand for one collaboration pattern (strategy parameter), or maybe more? + are there subcollaborations within one adjuster (read subtraversals in which case the "during" construct by Karl may be needed)? As an aside, like Doug, I am also not sure what the purpose of the "during s" phrase is. - scalability: how easy is it to build "a bit more sophisticated" scenarios as layers (or towers) of adjusters? - relationship between adjusters and visitors: Karl tends to make a strong distinction between them: KL> We have two kinds of application-specific design patterns KL> both being class graph modifiers: KL> adjusters and visitors. KL> An adjuster modifies a group of classes permanently and is used KL> outside the scope of a strategy. KL> A visitor also modifies a group of classes but the KL> modifications are only felt during some traversal. KL> A visitor is used in the scope of a strategy. I am not sure about the meaning of "outside the scope of a strategy" above. I feel like there is no essential difference. The difference I see is that adjusters define structure-shy collaborative behavior which is not very traversal intensive, while visitors define traversal intensive behavior. As we have used them recently, a (plug-and-play) visitor defines one single piece of functionality over a whole class graph (e.g. dft of a graph) the core of which is a traversal of the class graph. However, I tend to see them as essentially the same, and would like to have a uniform name fro both. I guess, that by distinguishing between "modifications are only felt during some traversal" and "modifies a group of classes permanently and is used outside the scope of a strategy", Karl has the view of adjusters as a package of classes and visitors as objects in mind. Is that right?