From: Niklas Holsti <niklas.holsti@tidorum.invalid>
Subject: Re: how to organize source code for a complete software? Thanks!
Date: Sun, 09 Oct 2011 19:48:34 +0200
Date: 2011-10-09T19:48:34+02:00 [thread overview]
Message-ID: <9fe53iFoe7U1@mid.individual.net> (raw)
In-Reply-To: <j6shle$h5f$1@dont-email.me>
On 11-10-09 18:20 , Jinsong Zhao wrote:
> Hi there,
>
> I am new to Ada, and I just have some experiences in using Fortran.
Welcome, then. May I ask what attracted you to Ada? I am asking partly
out of curiosity, but also because if you tell us what you hope to gain
by using Ada, we may better advise you on how to organize your code, and
on other Ada usage.
> When using Fortran, I generally put each subroutine or function in a
> separate file, e.g., dot.for for dot product of two vectors. Then a
> main.for that call the necessary subroutine or functions. It seems to be
> rational.
>
> When I using Ada, I don't know how to do.
If you like, you can do exactly as you are accustomed to doing in
Fortran (although this would be an unusual style for Ada). You can put
each Ada function or procedure in its own compilation unit.
The only difference is that you will typically write two files per
subprogram, one to specify the subprogram (its name, its parameters, and
its return type, if it is a function) and one to implement the
subprogram by giving its body, which contains the declarations of the
local variables and the statements that are executed in the subprogram.
For example, let's make a function that adds two Float numbers and
returns their sum, and let's call this function Add. In the following, I
assume you are using the GNAT Ada compiler and its default conventions
for source file names.
The Add function will have a specification (or declaration) file
add.ads, which contains this one line:
function Add (A, B : Float) return Float;
Any other subprogram that needs to use (call) the Add function will
start with the line
with Add;
which makes the compiler read the file add.ads, so that the compiler
knows the name, parameters, and return type of Add.
The Add function will have an implementation (or body) file add.adb,
which contains these five lines:
function Add (A, B : Float) return Float
is
begin
return A + B;
end Add;
Assume that your main subprogram should use Add to compute the sum of
the numbers 15.6 and 88.2 and print out the sum, and you give this
procedure the name Main, then you would write it as the file main.adb
with the following content:
with Add; -- So that we can call Add, below.
with Ada.Text_IO; -- So that we can call Put_Line, below.
procedure Main
is
begin
Ada.Text_IO.Put_Line (Float'Image (Add (15.6, 88.2)));
end Main;
This program thus consists of three files: add.ads, add.adb, main.adb.
To compile this program with GNAT, you only have to give the command
gnatmake main
and GNAT will compile all three files and create an executable called main.
> There are procedure, function,
> package, package body, and so on (with different file extension, e.g.,
> ada, adb, ads, ...). And there is no main program.
The main program is just a parameterless procedure, like the Main above.
It can be called anything you like; its name usually (but not
necessarily) becomes the name of the program executable.
The one-subprogram-per-file method shown above, which is what you have
been doing in Fortran, breaks down when you have subprograms that need
to access some global data, for example like Fortran COMMON data. If you
don't want to pass all this data in parameters, you must put it in a
package. Then you can have two Ada designs, one that is very similar to
Fortran COMMON, and the other that is more typical for Ada.
Here is how to do the Fortran-like design. Suppose that the Add
function, above, should also include in the sum the value of a global
variable Offset, that relates to some "scale" that the program is using,
but you don't want to pass Offset as a parameter to Add. In Fortran, you
could declare a COMMON area called Scale, containing a variable called
Offset. In Ada, this can be implemented as a package Scale with a public
variable Offset. Such a package is written in one file, scale.ads, as
follows:
package Scale
is
Offset : Float := 0.0;
end Scale;
Here I also gave the Offset an initial value, just to avoid using an
undefined value.
The Add function would now be written as follows, in add.adb:
with Scale;
function Add (A, B : Float) return Float
is
begin
return A + B + Scale.Offset;
end Add;
Note that:
- the line "with Scale" gives us access to the data in Scale, but
- you still have to use the qualified name, Scale.Offset, to refer
to the variable Offset in the package Scale.
If you add a line after "with Scale", saying "use Scale", you can use
just the name Offset instead of Scale.Offset. But many Ada programmers
think that such "use clauses" should be used very sparingly, and that
writing Scale.Offset is clearer.
Note that the file add.ads was not changed, since the text in that file
does not have to refer to the Scale package.
Suppose now that your Main subprogram needs to Add the same two numbers
as before, but with an Offset of 3.2. This would be written as follows,
in main.adb:
with Add; -- So that we can call Add, below.
with Scale; -- So that we can access Scale.Offset, below.
with Ada.Text_IO; -- So that we can call Put_Line, below.
procedure Main
is
begin
Scale.Offset := 3.2;
Ada.Text_IO.Put_Line (Float'Image (Add (15.6, 88.2));
end Main;
> Would anyone here like to give a an analogy between the source code
> organization in Fortran and the one in Ada?
The example above was how one would represent Fortran COMMON in Ada
packages, in a Fortran-like way: write the COMMON area as a package
(*.ads file) with public variables representing the COMMON data, and
then "with" this package in any subprogram (*.adb file) that needs to
use this data.
However, this style is not the typical Ada style. The more common style
in Ada is to make packages that contain both data and subprograms, and
to make the data private as far as possible.
This is stretching the above example a bit, but the principle would be
to put the Add function in the Scale package, since it needs to use
Scale.Offset, and to move the Offset variable into the package body, so
that it cannot be accessed from outside the package. The file scale.ads
would now look like this:
package Scale
is
function Add (A, B : Float) return Float;
procedure Set_Offset (To : in Float);
end Scale;
The declaration of the Offset variable, and the bodies of the two
subprograms, would now be written in the "body file" for Scale, which is
called scale.adb and contains this:
package body Scale
is
Offset : Float := 0.0;
function Add (A, B : Float) return Float
is
begin
return A + B + Offset;
end Add;
procedure Set_Offset (To : in Float)
is
begin
Offset := To;
end Set_Offset;
end Scale;
Of course, the files add.ads and add.adb are now unnecessary, since Add
is both declared and implemented within package Scale, thus in the files
scale.ads and scale.adb.
The Main subprogram in main.adb would now have this form:
with Scale; -- So that we can use it, below.
with Ada.Text_IO; -- So that we can call Put_Line, below.
procedure Main
is
begin
Scale.Set_Offset (3.2);
Ada.Text_IO.Put_Line (Float'Image (Scale.Add (15.6, 88.2));
end Main;
The single command "gnatmake main" is still enough to compile the
program, although Main now uses other packages.
If you have any other subprograms that are also related to the Scale,
and need to use Scale.Offset, you would put them in package Scale, too.
Of course, finding a good package structure can become complex if you
have something like a Fortran program with several COMMON areas, and
have several subprograms that use different subsets of the COMMON areas.
You can fall back on the Fortran-like structure (one package per COMMON
area, with public data), or look up some texts on "information hiding"
and "software architecture", but even so, there are usually several ways
to slice the cake, and the best way is often a matter of taste.
> And, please, if you like, point me a small, complete open source
> software in Ada (not a library or package). I should be compiled and
> run. I just hope to learn how to start a software in Ada by example.
Sorry, my internet access at present (on travel) is so wonky that I have
no web access, in practice.
--
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
. @ .
next prev parent reply other threads:[~2011-10-09 17:48 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-10-09 16:20 how to organize source code for a complete software? Thanks! Jinsong Zhao
2011-10-09 17:16 ` stefan-lucks
2011-10-10 5:52 ` Jinsong Zhao
2011-10-09 17:37 ` Yannick Duchêne (Hibou57)
2011-10-10 6:02 ` Jinsong Zhao
2011-10-10 13:15 ` Paul Colin Gloster
2011-10-10 15:46 ` Simon Wright
2011-10-10 19:03 ` RasikaSrinivasan@gmail.com
2011-10-10 22:12 ` Randy Brukardt
2011-10-09 17:48 ` Niklas Holsti [this message]
2011-10-09 18:37 ` Ludovic Brenta
2011-10-09 21:24 ` J-P. Rosen
2011-10-10 12:09 ` Jinsong Zhao
2011-10-10 6:45 ` Jinsong Zhao
replies disabled
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox