views:

46

answers:

1

Hi, I have a query with declarative part, function and packages. I have a package as shown next. Due to the complexity of the Compute_X1 function, I have create a "is separate" for computing this function. The value returned from Compute_X1 is X1 and is to be used in the function J21 (J21 takes X1 as a first argument).

Package specification:

package Compute_Jacobian is

--compute X1
function Compute_X1 ( Force_Applied, Forcing_Frequency: Long_Float) return Long_Float;

--- use X1 in J21
function J21 ( X1, Forcing_Frequency, Natural_Frequency : Long_Float) return Long_Float;

end Compute_Jacobian;

The package body is:

package body Compute_Jacobian is
 --compute X1

function Compute_X1 ( Force_Applied, Forcing_Frequency: Long_Float) return Long_Float is separate;

X1 := Compute_X1 ( Force_Applied, Forcing_Frequency);


function J21 ( X1, Forcing_Frequency, Natural_Frequency : Long_Float) return Long_Float is separate;

end Compute_Jacobian;

and I have created stubs for Compute_X1 and J21.

On compiling the package body Compute_Jacobian.adb, I get this error message:

12.    X1 := Compute_X1 ( Force_Applied, Forcing_Frequency);
       |
    >>> statement not allowed in declarative part

My question is how to compute X1 and use it in the computation of function J21.

I could try to compute X1 in the "main" code (not shown here) directly (making a "is separate" from there) and then use it as a normal argument in computing J21. But I wanted the above structure (in my above post here) with computation of X1 in the Compute_Jacobian package.

Thanks a lot...

+2  A: 

Well, the compiler is telling you exactly what the problem is :-)

You're trying to execute an assignment statement in a region of the code that permits only declarations.

At the very least I don't see your declaration of X1 (although that may be because you don't excerpt it in the above code), nor do I see declarations and values being assigned to Force_Applied and Forcing_Frequency.

This can be fixed up so that it will compile close to as-is:

X1 : Long_Float := Compute_X1 ( Force_Applied, Forcing_Frequency);

or, by adding an initialization block to the package body:

package body Computer_Jacobian is
    ...
    X1 : Long_Float;
    ...
begin
   X1 := Compute_X1 ( Force_Applied, Forcing_Frequency);
end Compute_Jacobian;

But honestly, I really don't think either of these is what you really want.

In your main program you could just declare X1 (and the variables being passed as arguments) and then invoke your Compute functions, e.g. (warning, not compiled)

with Compute_Jacobian;
procedure Do_Computations is

  Force_Applied     : Long_Float := 1.0;
  Forcing_Frequency : Long_Float := 10.0;
  Natural_Frequency : Long_Float := 5.0;

  X1  : Long_Float;
  J21 : Long_Float;

begin
   X1  := Compute_Jacobian.Compute_X1 (Force_Applied, Forcing_Frequency);
   J21 := Compute_Jacobian.Compute_J21 (X1, Forcing_Frequency, Natural_Frequency);
end Do_Computations;

This is one approach to getting what you might be looking for.

Or if X1 is used solely within Compute_J21, you should just invoke Compute_X1 as one of the first statements executed (or as an initialization of the X1 declaration) within that function (and pass Force_Applied, instead of X1, as a argument to Compute_J21):

function Compute_J21 (Force_Applied, 
                      Forcing_Frequency,
                      Natural_Frequency : Long_Float)
                                   return Long_Float is

   -- Declarations...
   X1 : Long_Float := Compute_X1(Force_Applied, Forcing_Frequency);

begin
   -- Computations that utilize X1...

end Compute_J21;

And one note about the use of "is separate"... I understand the urge to set those function implementations apart because of their complexity, but I would still recommend against doing so. It simply adds another file to keep track of, if you're using GNAT you don't get any performance gain by just trying to compile them separately since the whole package body ends up getting processed anyway, and using "is separate" is now pretty uncommon in mainstream Ada programming. This answer covered some of this in a previous question you'd asked.

Marc C
Many thanks. In fact your first solution made me realize that I didn't declare X1 at all in code. And you have provided me with several alternatives that will help me think a bit on the most appropriate one to use here. I have been focusing too much to write stubs which contain very long mathematical expressions (that can be visualized on A3 paper in landscape mode).
yCalleecharan
Yes, it was pointed out that is "separate" is not ok and you were one of the persons to tell this. At the level of my understanding, I don't know if I can do away with "is separate". I provided a minimal example above but I have several functions like J21, J22, etc. to compute. As these are long expressions, I am writing an "is separate" for each of them. I can't think of putting them in a single body and having to scroll up and down on the screen. After I test a separate "is separate" unit, I forget it as I know its works fine. By having all in 1 code, I fear of putting accidental typos.
yCalleecharan
I tried the software "Understand" and it's very useful to know the inter-relationships between files. I don't see that GPS has such a graphical feature. I am the only one to maintain my code and so I'm doing what I can to make it simple for me. But of course I would like to learn the correct way and minimizing the use of "is separate". I see that since I learned Ada and its separate compilation units, I'm more inclined to keep my main code very compact and uncluttered from too much numerical mathematical expressions. A large part of the maths end up in "is separate" units if they are long.
yCalleecharan
1 vote up for providing all these alternative solutions.
yCalleecharan
As far as using "separate" goes, if it works for you, then it works for you. It's not wrong, it's just little used nowadays. And I second your use of "Understand", I've used that tool for many years now, and it has proven absolutely essential for projects where I had to deal with very large legacy code bases.
Marc C
Thanks. If I didn't know Ada, I would have managed putting the long maths expressions in subprograms somehow in C or Matlab. And this would cause confusion to me after some time. To write the expressions for 1 single function (such as J21 in my code) is taking almost 1 A3 page of Ada code. If I would put two or more functions like J21 in the same file, it would been quite difficult for me to handle the file contents after some time. So yes maybe in my case I should say thanks to "is separate" units :).
yCalleecharan
Do you happen to know of other similar tools like "Understand" which are free? "Understand" is very much expensive.
yCalleecharan
Generally (and this has *always* been the case), if you are tempted to use `is separate`, then your code needs a serious refactoring. You should almost never have a routine that takes up more than a couple hundred or so lines of text, and rarely more than an hundred. If you have one that's over a thousand and seems to deserve its own source file, you probably have a the makings of a package or three buried in there. Thus using `is separate` is like tacking a huge "REWRITE ME!" sign on your code. That's why nobody uses it much.
T.E.D.
Thanks. I don't really get what you are saying. I'm computing a Jacobian matrix (a matrix of partial derivatives). Some elements of this matrix are very long mathematical expressions. I have a package Compute_Jacobian package (ads and adb) that have all the functions to compute the elements. But then when a jacobian element matrix is long (like J21 in my code), I have an "is separate" for it in my Compute_Jacobian package. I don't understand what you mean to create more packages if I have several lines in a "is separate" file. Can you please explain a little better?
yCalleecharan
In my Compute_Jacobian (adb), I have the maths expressions for jaobian matrix elements that are short. But when a jacobian matrix elements takes many lines to write, then I have an "is separate" for it. If I didn't create an "is separate", then I will have my Compute_Jacobian.adb with some short maths expressions together with some very long maths expressions. This will surely cause me to to scroll up and down to go through my code. This will make it difficult for me to handle. If I can do things differently, please let me know...I'm only willing to write better code.
yCalleecharan