Search code examples
functionpackageadadeclarative

Ada: declarative part, function and packages


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...


Solution

  • 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.