I'm with a mechanical engineering background but I'm interested to learn good software engineering practice with Ada. I have a few queries.
Q1. If I understand correctly then someone can just write a package specification (ads) file, compile it and then compile the main program which is using the package. Later on, when one knows what to include in the package body then the latter can be written and compiled. Afterwards, the main program can now be run. I've tried this and I would like to confirm that this is good practice.
Q2. My second question is about stubs (sub-units) and the use of SEPARATE. Say I have a main program as follows:
WITH Ada.Float_Text_IO;
WITH Ada.Text_IO;
WITH Ada.Integer_Text_IO;
PROCEDURE TEST2 IS
A,B : FLOAT;
N : INTEGER;
PROCEDURE INPUT(A,B: OUT FLOAT; N: OUT INTEGER) IS SEPARATE;
BEGIN -- main program
INPUT(A,B,N);
Ada.Float_Text_IO.Put(Item => A);
Ada.Text_IO.New_line;
Ada.Integer_Text_IO.Put(Item => N);
END TEST2;
Then I have the procedure INPUT in a separate file:
separate(TEST2)
PROCEDURE INPUT(A,B: OUT FLOAT; N: OUT INTEGER) IS
BEGIN
Ada.Float_Text_IO.Get(Item => A);
Ada.Text_IO.New_line;
Ada.Float_Text_IO.Get(Item => B);
Ada.Text_IO.New_line;
Ada.Integer_Text_IO.Get(Item => N);
END INPUT;
My questions:
a) AdaGIDE suggests me to save the the INPUT procedure file as input.adb. But then on compiling the main program test2, I get the warning:
warning: subunit "TEST2.INPUT" in file "test2-input.adb" not found
cannot generate code for file test2.adb (missing subunits)
To AdaGIDE, this is more of an error as the above warnings come before the message:
Compiling...
Done--error detected
So I renamed the input.adb file to test2-input.adb as was suggested to me by AdaGIDE on compiling. Now on compiling the main file, I don't have any warnings. My question now is if it's ok to write
PROCEDURE INPUT(A,B: OUT FLOAT; N: OUT INTEGER) IS
as I did in the sub-unit file test2-input.adb or is it better to write a more descriptive term like
PROCEDURE TEST2-INPUT(A,B: OUT FLOAT; N: OUT INTEGER) IS
to emphasize that procedure input has a parent procedure test2 ? This thought follows from AdaGIDE hinting me about test2-input.adb as I mentioned above.
b) My next question:
If I understand well the compilation order, then I should compile the main file test2.adb first and then the stub test2-input.adb . On compiling the stub I get the error message:
cannot generate code for file test2-input.adb (subunit)
Done--error detected
However, I can now do the binding and linking for test2.adb and run the program .
I would like to know if I did wrong by trying to compile the stub test2-input.adb or should it not be compiled?
Q3. What is the use of having subunits? Is it just to break a large program into smaller parts? I know an error arises if one doesn't put any statements between BEGIN and END in the subunit. So this means that one always has to put a statement there. And if one wants to write the statements later, one can always put a NULL statement between between BEGIN and END in the subunit and comes back to the latter at a later time. Is this how software engineering is done in practice?
Thanks a lot...
Q1: That is excellent practice.
And by treating the package specification as a specification, you can provide it to other developers so that they will know how to interface to your code.
Q2: I believe that AdaGIDE actually uses the GNAT compiler for all compilation, so it's actually GNAT that is in charge of the acceptable filenames. (This can be configured, but unless you have a very compelling reason to do so, it is far simpler to simply go with GNAT/AdaGIDE's file naming conventions.) More pertinent to your question, though, there's no strong reason to include the parent unit as part of the separate unit's name. But see the answer to Q3...
Q3: Subunits were introduced with the first version of Ada--Ada 83--in part to help modularize code, and allow for deferred development and compilation. However, Ada software development practice has pretty much abandoned the use of subunits, all the procedure/function/task/etc bodies are simply all maintained in the body of the package. They are still used in some areas, like if a platform-specific version of subprogram may be needed, but for the most part they're rarely used. It leaves fewer files to keep track of, and keeps the implementation code of a package all together. So I strongly recommend you simply ignore the subunit capabilities and place all your implementation code in package bodies.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With