From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-0.3 required=5.0 tests=BAYES_00, REPLYTO_WITHOUT_TO_CC autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,18f6de557e6897b2 X-Google-Attributes: gid103376,public From: "John G. Volan" Subject: Re: circular unit dependency Date: 1997/06/01 Message-ID: <33924229.78A1@sprintmail.com> X-Deja-AN: 245542243 References: <3386d96f.171920@noticias.ibernet.es> <9A7E8196B8D7EE83.E6C868B798076E45.6F1AD9E8B3E01F66@library-proxy.airnews.net> <3390987B.60DD@sprintmail.com> <1AF3D92DC96C496B.A46C2A085C1A7ABB.48C9498C8799EABA@library-proxy.airnews.net> Organization: Sprint Internet Passport Reply-To: johnvolan@sprintmail.com Newsgroups: comp.lang.ada Date: 1997-06-01T00:00:00+00:00 List-Id: [Looks like one of my posts got lost, so let me try it again. Apologies if it appears after all...] Kevin Cline wrote: > > "John G. Volan" wrote: > > >Au contraire, mon frere! Class1 may be useful in contexts 1, 2, 3 and 4; > >class2 in contexts 3, 4, 5 and 6. If I am writing client code in > >context 1 or 2, why should I care a whit about Class2? > > It doesn't matter which ones you "care" about. To use either, you have to > link both package bodies. Well, of course they both have to be _linked_ together. After all, the premise is that Class1 and Class2, in some aspect of their functionality, collaborate with each other. So of course they had both better exist within the same executable. But the issue is not whether these two classes have to be _linked_ together; the issue is whether they have to be _used_ together, by all of their various clients within that executable. In other words, does the fact that Class1 and Class2 happen to be clients of each other necessarily mean that every _other_ client of Class1 is _always_ going to be a client of Class2 as well (and vice versa)? What if their mutual collaboration is only one small aspect of their respective functionalities? What if, in particular, Class1 participates in collaborations with other classes that Class2 is not directly involved with (and vice versa)? For instance, suppose Class2 mutually collaborates with Class3, but that Class3 does not collaborate directly with Class1. In other words, the designer of Class3 should be able to write all the Class3 operations that involve Class2 entirely in terms of a subset of Class2 operations that only involve Class3. According to the design of the application, there is absolutely no need for Class3 to mention Class1 at all. According to you, however, we are forced to put Class3 in the same package with Class2. But Class2 (according to you) is already in the same package with Class1. So Class3 is now in the same package with Class1. This package is starting to get a bit hefty now. What if, meanwhile, Class1 is collaborating with Class4, and this aspect of its functionality is independent of its involvement with Class2? Your package has to swallow up Class4 as well. This, despite the fact that the connection between Class3 and Class4 is quite tenuous, there being no less than three layers of abstraction between them: Class3<-->Class2<-->Class1<-->Class4 Or at least, there would have been, if we hadn't been so busy pointedly dissolving those layers of abstraction. As we expand our viewpoint to take in more and more of the classes in our class-association diagram, what if we find that Class2 has another association, with Class5, and Class5 has a totally independent association with Class6? Yup -- those puppies get tossed right into the ravenous maw of our class-eating monster package. > The package interface and package body are two > separate aspects of a single software component. Yeah, so? What's your point? > Circular dependencies > between components should be avoided. Why? This sounds like a religious statement. Or rather, it sounds like the kind of statement that was once made by various authorities in the Ada world back in the early days of Ada83. I should point out that, in this object-oriented age, those very same authorities have since come around to the viewpoint that, well, sometimes circular dependency -- or rather, mutual client-server dependency between object-classes -- is not only okay, but in fact is downright necessary. Even Tucker Taft has said that Ada95 ought to be modified to help enable that. What exactly is so bad about mutual dependency? Class1 is a client of Class2. Why should the way I implement that be different depending on whether or not Class2 also coincidentally happens to be a client of Class1? Isn't co-encapsulation worse than mutual dependency? Consider: Suppose, as I advocate, we separately encapsulate Class1, Class2, Class3, and Class4, despite their various mutual dependencies. Now suppose the interface to Class4 has to change. (Let's say we discover that we need Class7 to collaborate with Class4, so we introduce some operations to cover that aspect of Class4's functionality.) The body of Class1 has to be recompiled, yes, but (if the association is really independent) Class1 shouldn't have to be modified. In particular, the interface of Class1 shouldn't have to be modified. In fact, the whole point to any workaround to the "withing" problem is that Class1's interface isn't dependent on the full interface for Class4, but only on some kind of "forward declaration" of Class4. So the Class1 package spec shouldn't have to change, and it shouldn't have to be recompiled. This means that Class2 doesn't have to be recompiled, and Class3 doesn't have to be recompiled, and so on and so on. More important than just the CPU time we don't have to spend running the compiler, is the human time we don't have to spend worrying whether Class2, Class3, and so on need to be re-written. After all, Class1 is supposed to be an abstraction, and nothing about that abstraction has changed as far as Class2 is concerned. And Class3, etc. haven't even _heard_ of Class1! But if, as you suggest, all these classes have been sucked down a black hole into a single-package singularity, then recompiling one class means recompiling them all. Worse than the CPU time spent running the compiler is the human time that needs to be spent making sure that the changes we made in introducing Class7 don't somehow affect any of the other classes in the package. With no clear package boundaries separating them, we can't be sure unless we do some deep analysis -- and that takes human mental effort, which means $$$. ------------------------------------------------------------------------ Internet.Usenet.Put_Signature (Name => "John G. Volan", Employer => "Texas Instruments Advanced C3I Systems, San Jose, CA", Work_Email => "johnv@ti.com", Home_Email => "johnvolan@sprintmail.com", Slogan => "Ada95: World's *FIRST* International-Standard OOPL", Disclaimer => "My employer never defined these opinions, so using" & "them would be totally erroneous ... or is that" & "just nondeterministic behavior now? :-) "); ------------------------------------------------------------------------