comp.lang.ada
 help / color / mirror / Atom feed
From: Brad Moore <brad.moore@shaw.ca>
Subject: Re: Proper program structure
Date: Thu, 01 Oct 2009 23:44:20 -0600
Date: 2009-10-01T23:44:20-06:00	[thread overview]
Message-ID: <6rgxm.83139$u76.321@newsfe10.iad> (raw)
In-Reply-To: <35f850af-2aed-4fe8-be6d-473ab698c181@h13g2000yqk.googlegroups.com>

Maciej Sobczak wrote:
> On 1 Paz', 17:36, Brad Moore <brad.mo...@shaw.ca> 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



  reply	other threads:[~2009-10-02  5:44 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-09-30 21:25 Proper program structure Maciej Sobczak
2009-09-30 22:16 ` Robert A Duff
2009-10-01  7:13   ` Maciej Sobczak
2009-09-30 23:43 ` Adam Beneschan
2009-10-01  7:35   ` Maciej Sobczak
2009-10-01  6:34 ` Brad Moore
2009-10-01  7:44   ` Maciej Sobczak
2009-10-01  9:39   ` Maciej Sobczak
2009-10-01 15:36     ` Brad Moore
2009-10-01 20:01       ` Maciej Sobczak
2009-10-02  5:44         ` Brad Moore [this message]
2009-10-02 13:10           ` Brad Moore
2009-10-01  8:08 ` Dmitry A. Kazakov
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox