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.8 required=5.0 tests=BAYES_00,PLING_QUERY autolearn=no autolearn_force=no version=3.4.4 X-Google-Thread: a07f3367d7,2f6e39a9d25bcd8b X-Google-Attributes: gida07f3367d7,public,usenet X-Google-NewGroupId: yes X-Google-Language: ENGLISH,ASCII-7-bit Path: g2news2.google.com!news3.google.com!fu-berlin.de!uni-berlin.de!individual.net!not-for-mail From: Niklas Holsti Newsgroups: comp.lang.ada Subject: Re: how to organize source code for a complete software? Thanks! Date: Sun, 09 Oct 2011 19:48:34 +0200 Organization: Tidorum Ltd Message-ID: <9fe53iFoe7U1@mid.individual.net> References: Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-Trace: individual.net koYm1DG6Ks7jaP5ZLnIW6wCAyGrSLuWp2tBkVzQDaYe8Z8Uqeq Cancel-Lock: sha1:JGF1OiEAcrLCHxn1u++S0266Q+Y= User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:6.0.2) Gecko/20110902 Thunderbird/6.0.2 In-Reply-To: Xref: g2news2.google.com comp.lang.ada:22311 Date: 2011-10-09T19:48:34+02:00 List-Id: 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 . @ .