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 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Thread: a07f3367d7,efde8669839c1c0a X-Google-Attributes: gida07f3367d7,public,usenet X-Google-NewGroupId: yes X-Google-Language: ENGLISH,ASCII-7-bit Path: g2news2.google.com!news4.google.com!proxad.net!feeder1-2.proxad.net!news.glorb.com!npeer02.iad.highwinds-media.com!news.highwinds-media.com!feed-me.highwinds-media.com!post01.iad.highwinds-media.com!newsfe10.iad.POSTED!7564ea0f!not-for-mail From: Brad Moore User-Agent: Thunderbird 2.0.0.23 (X11/20090817) MIME-Version: 1.0 Newsgroups: comp.lang.ada Subject: Re: Proper program structure References: <638d582c-f275-48a9-aa2a-237f2edd123c@c37g2000yqi.googlegroups.com> <35f850af-2aed-4fe8-be6d-473ab698c181@h13g2000yqk.googlegroups.com> In-Reply-To: <35f850af-2aed-4fe8-be6d-473ab698c181@h13g2000yqk.googlegroups.com> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 8bit Message-ID: <6rgxm.83139$u76.321@newsfe10.iad> NNTP-Posting-Host: 70.72.159.148 X-Complaints-To: internet.abuse@sjrb.ca X-Trace: newsfe10.iad 1254462274 70.72.159.148 (Fri, 02 Oct 2009 05:44:34 UTC) NNTP-Posting-Date: Fri, 02 Oct 2009 05:44:34 UTC Date: Thu, 01 Oct 2009 23:44:20 -0600 Xref: g2news2.google.com comp.lang.ada:8568 Date: 2009-10-01T23:44:20-06:00 List-Id: Maciej Sobczak wrote: > On 1 Paz', 17:36, Brad Moore wrote: > >> OK, but I can apply a similar technique to hide the routines from the >> public interface of the car. In this case, I renamed the Cars.Vehicle >> package to be Cars.Vehicle_Internal, then created a public Cars.Vehicle >> package that wraps the internal one, but hides the interfaces that you >> do not want to expose. >> >> Is this version acceptable? > > Well, it is acceptable in the same way as the other options that I > have described. In other words, due to the fact that the right way > does not work, I have to use some inferior solution that always has a > price in the design that does not accurately reflect the original > intent. > > Thank you very much for you complete examples, but I have finally > settled on two-phase initialization of components (so each has an Init > procedure that is used to wire them together and all Inits are called > from the constructor of the whole). This solution allows to keep the > reasonable package hierarchy (no artificial packages are needed) and > avoids a number of forwarding subprograms. You're welcome. It was an interesting challenge. Not sure I fully see how you've structured things, but glad you found something that at least works. I do have one more set of refinements to add to my example though. I can get rid of the artificial packages Cars, and Vehicle, by using an incomplete type declaration. That is, I move the declarations in Cars.Vehicle, to Cars, which is where you wanted to declare the type in the first place. However Vehicle_Type is an access type to an incomplete type that is completed in the body. This allows me to delete the Cars.Vehicle package as it is no longer needed. Since Construct now returns a heap allocated object, I make the type, Vehicle_Internal_Type a controlled type in the package body, so that clients of Cars would not be impacted by memory leakage by declaring a Vehicle_Type on the stack. Also, I made the Cars.Vehicle_Type inherit from Cars.Vehicle_Internal.Vehicle_Internal_Type. That way, I eliminate the forwarding programs. (If that is what you meant by forwarding subprograms), since the primitive subprograms are inherited directly. Well not entirely true. The primitive subprograms are available in the body, but if they need to be exported from the spec, then you still need forwarding subprograms, since Vehicle_Type is an access type. Also, other than the Cars package, all the other child packages are private packages, which cannot be withed by client code. If the goal of this exercise is to be able to define a clean interface that is not impacted by the Ada language restrictions, ie, no evidence or artifacts in the spec resulting from issues that have been discussed, then I think this might be a good approach. If we had to jump through a hoop or two to get the implementations to work, at least we've hidden those hurdles. Of course, the approach you've chosen may still be a better approach for you, since the requirements of your real system may be very much different than this toy example. For example, you may not like the fact that I used heap allocation here, or that I still have a Cars.Vehicle_Internal package, though that is a private package at least. Maybe it just needs a better name. It is perhaps weird that the vehicle_type in Cars effectively inherits from a private child package. Usually it is the other way around, the child package type inherits from the root package type, but I think this gives you the effect that the root package type contains all the details hidden in the child package. To show the refined approach though... package Cars is type Vehicle_Type (<>) is limited private; function Construct return Vehicle_Type; private type Car_Type; type Vehicle_Type is access all Car_Type; end Cars; ------------------------------------------ with Cars.Vehicle_Internal; use Cars.Vehicle_Internal; package body Cars is type Car_Type is new Vehicle_Internal_Type; function Construct return Vehicle_Type is begin return new Car_Type' (Car_Type (Vehicle_Internal_Type'(Construct))); end Construct; end Cars; --------------------------------------------- with Cars.Types; use Cars.Types; private with Cars.Wheels, Cars.Chassis, Cars.Engine, Cars.Gear_Box; private with Ada.Finalization; private package Cars.Vehicle_Internal is type Vehicle_Internal_Type is private; procedure Shift_Gears (Car : in out Vehicle_Internal_Type; Gear : Gear_Type); function Construct return Vehicle_Internal_Type; private use Cars.Wheels, Cars.Chassis, Cars.Engine, Cars.Gear_Box; use Ada.Finalization; type Wheel_Array_Type is array (1 .. 4) of Wheel_Type; type Force_Finalization is new Controlled with null record; type Vehicle_Internal_Type is record Needs_Finalization : Force_Finalization; Wheels : Wheel_Array_Type; Chassis : Chassis_Type; Engine : Engine_Type; Gear_Box : Gear_Box_Type (Vehicle_Internal_Type'Access); end record; end Cars.Vehicle_Internal; ---------------------------------------- package body Cars.Vehicle_Internal is function Construct return Vehicle_Internal_Type is begin return New_Vehicle : Vehicle_Internal_Type do Gear_Box.Select_Gear (New_Vehicle.Gear_Box, Park); return; end return; end Construct; procedure Shift_Gears (Car : in out Vehicle_Internal_Type; Gear : Gear_Type) is begin Cars.Engine.Shift_Gears (Motor => Car.Engine, Gear => Gear); end Shift_Gears; end Cars.Vehicle_Internal; ---------------------------------------- -- Also, forgot to include this package last time. private package Cars.Types is type Gear_Type is (Park, Neutral, Forward, Backward); end Cars.Types; Brad