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=-1.9 required=5.0 tests=BAYES_00, T_FILL_THIS_FORM_SHORT autolearn=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,d7888dd6424b687 X-Google-Attributes: gid103376,public From: matthew_heaney@acm.org (Matthew Heaney) Subject: Re: Uncle Date: 1998/05/24 Message-ID: X-Deja-AN: 356166596 Content-Transfer-Encoding: 8bit References: <6jlk5s$mob@tomquartz.niestu.com> Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Organization: Network Intensive Newsgroups: comp.lang.ada Date: 1998-05-24T00:00:00+00:00 List-Id: In article <6jlk5s$mob@tomquartz.niestu.com>, chipr@niestu.com (Chip Richards) wrote: >On to specific questions. First, there's an Object type (a tagged record--an >*abstract private* tagged record at the moment, because that seemed like the >right thing to do), from which about half the various widget types are >derived, and a Composite type (called "puInterface" in the original code) >which is derived from Object, and from which the rest of the widgets are >derived. Composite adds a pointer to a list of child Object items, and each >Object contains a pointer to its parent Composite. Since the two types are >interdependent in this way, they must be declared in the same package spec, >right? No other choice? So my urge to make Composites a child package off >Objects is misguided? This idiom is straight out of the GofF book (see the Composite pattern). As always, the answer is, "It depends." What is a composite doing to its children? It sounds like they need to go in the same package, but, you could just declare the root of the object hierarchy and just the primitive operations needed by composite, in package visitible to the composite package. For example, package PUI Is type Root_Object is abstract tagged ...; type Object_Access is access all Root_Object'Class; type Object_List is ...; type Root_Composite is abstract tagged record List : Object_List; end record; end PUI; >Right now, Object and Composite are defined in the topmost package, called >"PUI", along with their primitive operations. There are child packages >PUI.Objects and PUI.Composites, which define various related procedures, but >only "internal" ones--all the user-visible subprograms that operate directly >on those two types are also in package PUI. I already don't like that >structure, but I've got more pressing problems at the moment. Why don't you like that structure? I think you could just isolate the primitive operations just required by composite in the scope visible to the composite type. That's what I did above. You can still have child packages, as in package PUI.Objects is type Object is new Root_Object with ...; end; package PUI.Composites is -- -- I don't know if you really need this package. -- type Composite is new Root_Compositive with ...; end; What you could do is move the declaration of root object into the private region of PUI; then those "special operations" needed only by composite could be declared there, so only children (like Composites) would have visibility. The "real" object type is declared its own package, as above. Something like package PUI is ... private type Root_Object is abstract tagged ...; type Object_Access is access all Root_Object'Class; end PUI; with PUI.Composites; package PUI.Objects is type Object is tagged private; private type Object is new Root_Object with record Parent : Composite_Access; ... end record; end PUI.Objects; package PUI.Composite is type Composite is ...; type Composite_Access is access all Composite'Class; private type Object_List is ...; type Composite is tagged record List : Object_List; .... end record; end; Now Composite has visibility to (dispatching) operations of Object, which it can use to implement its own primitive operations. >One suggestion I've received is to combine Object and Composite into a single >type. I could do that, but it seems as if it would lose some information--all >Composites are Objects, but not all Objects are Composites. No, I don't think this is required. Because you're manipulating pointers to things, I don't think you have any real problem with mutual spec dependencies. Composite and Object can be declared in separate packages. Actually, you probably want to declare the Root_Object in the public part of PUI, because you probably need to declare it in the public part of Composite, as in package PUI.Composite is type Composite is ...; procedure Add_Child (C : in out Composite; Child : Root_Object'Class); or maybe procedure Add_Child (C : in out Composite; Child : Object_Access); ... end PUI.Composite; >In fact, my overall tendency is to want to put each of the various types and >their associated subprograms together in separate packages. And because most >of the "major" user-visible types are derived from Object (which is itself not >used at the "user" level), I tend to think in terms of defining Object in a >"parent" package, and making all the other packages children of it. However, >I'm starting to get the idea that this isn't a very good plan. Every time I >try to split the code into neat chunks, a powerful force seems to want me to >glom them into one giant package. Ugh. I think you can put them in separate child packages, though it may require a downcast in the body of composite (from Root_Object to just Object) or maybe the other way around (downcase from Root_Composite to Composite in the body of Objects). In any case, I think you need one root type visible to the other. Either this package PUI is type Root_Composite is ...; end; package PUI.Objects is type Object is ...; function New_Object (Parent : Composite_Access) return Object'Class; -- (ops only depend on Root_Composite, not PUI.Composites.Composite) end; with PUI.Objects; package PUI.Composites is type Composite is new Root_Composite ...; end; -or- package PUI is type Root_Object is ... end; with PUI.Composites; package PUI.Objects is type Object is new Root_Object ...; end; package PUI.Composites is type Composite is ...; procedure Add_Child (C : in out Composite; Child : in Object_Access); -- (ops only depend of Root_Object, not on PUI.Objects.Object) end; Without studying your application some more, I can't say which approach is better. But the general concept is that a root type (acting as a sort of type hook, to grab on to) must be available to the other. (Perhaps this root type can be declared in the private part of PUI, but I don't think so, because it's used as an argument to the other type's public, primitive operations.) >Many of my problems doubtless stem from my practice of patterning the Ada >structure after the C++ structure. I mean, the C++ is broken up into (fairly) >tidy separate little source files, which seemed like a nice structure to use. >This is starting to seem like more and more of a mistake, and my current >temptation is to rip the code apart and bolt it back together some other way. The language has a profound influence on the design of the application. It wouldn't surprise me one ounce that the C++ structure isn't appropriate for Ada. But don't give up yet, as I think it's possible to more or less follow the C++ structure. >But, which way? Should I create independent packages like, say, Objects (as >opposed to the current PUI.Objects) and Boxes, and include *those* in a main >"PUI" package? The problem with that is, for user programs to see primitive >ops of type Object, they would have to "with" package Objects. Now, to my way >of thinking, that's just silly--users don't use "Objects", they use "Buttons" >and "Sliders" and so forth. Including a seemingly useless package because the >language makes you do it that way seems wrong to me. I think it's best to have a package that acts as the root of the subsystem, and you are correct in creating a PUI package. All other packages should be children of PUI. >I'm pretty sure it's me and not the language, however, and I'm sure some of >you out there can do this stuff in your sleep. I'm open to any suggestions. >In case it matters, I'm using GNAT 3.10p under Linux. If you've gotten this >far, thanks very much for your time! Feel free to email any time. You should have other Ada users to talk to, and I am willing to help. (I'm trying to boostrap GNAT 3.10p under LinuxPPC. Maybe you can help me too...) Matt