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/05 Message-ID: <33970BAF.3F61@sprintmail.com> X-Deja-AN: 246368387 References: <3386d96f.171920@noticias.ibernet.es> <9A7E8196B8D7EE83.E6C868B798076E45.6F1AD9E8B3E01F66@library-proxy.airnews.net> <33932F31.4399@sprintmail.com> <3393D0E1.AC9@sprintmail.com> Reply-To: johnvolan@sprintmail.com Newsgroups: comp.lang.ada Date: 1997-06-05T00:00:00+00:00 List-Id: Matthew Heaney wrote: > > In article <3393D0E1.AC9@sprintmail.com>, johnvolan@sprintmail.com wrote: > > >Perhaps you just haven't worked on the kinds of problems where this > >issue arises. There are a lot of ways to skirt the issue (see section 3 > >of my FAQ for a few). But there are just some domains where this > >pattern is the most straightforward one, the one that preserves the most > >abstractions. > > Perhaps that's true. Bob Eachus and those guys gave examples the last time > we...um..."discussed" this ...um.. "issue" in the language, where recursive > packages neatly solved the problem. What is a "recursive" package? Do you mean a package encapsulating two types that are mutually dependent? Yes, that is a legitimate coding pattern too, but I disagree that it is always appropriate for every case of mutually-dependent types (i.e., types whose primitive operations include parameters of the other type). I even disagree that it is always appropriate for mutually _recursive_ types (types whose structures must contain references (e.g. access values) designating the other type). I think the key question is whether the types need access to each other's implementation details or just each other's interfaces. With regard to the past discussion of this topic: Although it became heated at times, I believe it always remained civil. I did make a point of criticizing all those conservative voices that kept denying there was a problem. I will continue to challenge anyone who continues to deny the problem. But I viewed it then, and I view it still, as an intellectual debate, not a personal or political one. This is why I chafed at those who tried to make it personal or political. I especially chafed at those who dogmatically repeated the litany: "Do it our way, or go program in something else." I stubbornly refused to do that, and instead proposed an Ada0Y solution (thus goading Norman Cohen and Tucker Taft to propose other comparable solutions), and kept pushing until I found a workaround that can be used today (and is). Now, who do you think has gone further to promote Ada, me or the dogmatics? > Right now I'm doing a job for a client who insisted that each ADT get its > own package (even if it were a nested one), even when colocating the types > would have been the most natural solution. The result is a bloody mess. This is why I have been trying to promote "1 package = 1 type" as a design pattern _among_ design patterns. Neither this pattern, nor the co-encapsulation pattern, should be viewed as the "One True Way". Each has _appropriate_ applications. Those who are dogmatic for one or the other, without weighing the design tradeoffs, are just displaying poor engineering judgment. And I for one am not afraid to call it that, when I see it, no matter how highly esteemed the personage involved. > The example is of a queue and its iterator. Obviously the iterator has to > know the representation of the queue, so it can iterate over it. But the > queue also keeps track of the iterators that have registered with it, so > that it can adjust the pointer if an element is removed from the queue. This is exactly the sort of case I had in mind where co-encapsulation _can_ be justified: The types are very tightly coupled, and need to know each other's _implementations_. But this case should be carefully distinguished from loosely coupled types that don't need to know each other's implementation details, yet still collaborate with each other in terms of each other's abstractions. > Now, this is certainly not the smartest way to do iteration (they didn't > need all that power, nor the attendent complexity), but the queue > abstraction was made unnecessarily complex because it didn't have > visibility to the representation of the iterator, which was in a nested > package. The simple solution would have been to just put the 2 types > together in the same package, so they could see each other's > representation. Hmm. I think there might be a way for you to satisfy your employer while at the same time simplifying your life a bit. Your boss wants the iterator type to be visible in its own package, fine. But who says it actually has to be _implemented_ there? Here's the idea: (1) Move your iterator type to a child of your container package. (2) Write an iterator implementation type inside your container package, but hide it in the private part. The container type and the iterator implementation type can know each other's implementation details. (3) Privately implement your iterator type in the child package using the ready-made iterator implementation type from the parent container package. package Containers is type Container_Type is ... private; ... -- primitive Container operations private type Iterator_Implementation_Type is ... ... -- primitive Iterator_Implementation operations type Container_Type is ... end Containers; package Containers.Iterators is type Iterator_Type is ... private; ... -- primitive Iterator operations private type Iterator_Type is record Implementation : Iterator_Implementation_Type; end record; end Containers.Iterators; In other words, Containers.Iterators is just a "skin" package providing access to something already built-in (but hidden) in the Containers package. You'll have to implement the Iterator_Type operations using delegation: Each Iterator_Type operation needs to explicitly call the corresponding Iterator_Implementation_Type operation. (Inheritance won't work, because you can't take privately-inherited features and make them public.) But this way, the real guts of the iterator implementation can be in the same package with the container guts. > This is the about the only degree of colocation I've ever seen necessary: 2 > types that are mutually dependent. I'm not suggesting put "24 types" > together in the same package, and agree completely that that would be a bit > confusing! (Though the reader of my examples posted on the SIGAda Patterns > WG home page should be warned: my toy examples all feature multiple types > per package!) > > My real issue is with this coding convention that's been floating around > for years, that says something like "Thou shalt put only one ADT per > package." If you blindly apply a rule like that, without any thought at > all (like on my current project), then you're going to make your code very > complex. The guideline should be stated "Don't put unrelated types > together in the same package," because that would increase coupling. (It > gives a client interested in only one of the types an unnecessary > compilation dependency on the other.) > > Glib application of the former rule is also a warning sign that the shop > isn't really thinking in Ada, and is confusing module and type. Natural > and elegant solutions are only effected by immersing oneself in the > language, and not fighting its idiosyncrasies. Violent agreement. :-) Just beware that, in fighting one dogma, you don't inadvertently promote another... ------------------------------------------------------------------------ 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? :-) "); ------------------------------------------------------------------------