comp.lang.ada
 help / color / mirror / Atom feed
* Static variables?
@ 1997-03-17  0:00 Viqar Abbasi
  1997-03-17  0:00 ` Robert Dewar
  1997-03-18  0:00 ` Jon S Anthony
  0 siblings, 2 replies; 10+ messages in thread
From: Viqar Abbasi @ 1997-03-17  0:00 UTC (permalink / raw)



Hello,

Is there a way to declare local variables in ADA subprograms to be 
STATIC?  That is, they retain the value that they had when the 
subprogram was last exited.  

Thanks for the insights,
Viqar




^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Static variables?
  1997-03-17  0:00 Static variables? Viqar Abbasi
@ 1997-03-17  0:00 ` Robert Dewar
  1997-03-18  0:00   ` nasser
  1997-03-18  0:00 ` Jon S Anthony
  1 sibling, 1 reply; 10+ messages in thread
From: Robert Dewar @ 1997-03-17  0:00 UTC (permalink / raw)



Viqar asks

<<Is there a way to declare local variables in ADA subprograms to be
STATIC?  That is, they retain the value that they had when the
subprogram was last exited.>>

This seems to be one of the most F asked FAQ's

The answer is to declare variables in the package body.





^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Static variables?
  1997-03-17  0:00 Static variables? Viqar Abbasi
  1997-03-17  0:00 ` Robert Dewar
@ 1997-03-18  0:00 ` Jon S Anthony
  1997-03-18  0:00   ` Samuel Tardieu
  1997-03-19  0:00   ` Robert Dewar
  1 sibling, 2 replies; 10+ messages in thread
From: Jon S Anthony @ 1997-03-18  0:00 UTC (permalink / raw)



In article <332D71FF.4773@cae.ca> Viqar Abbasi <viqar@cae.ca> writes:

> Is there a way to declare local variables in ADA subprograms to be 
> STATIC?  That is, they retain the value that they had when the 
> subprogram was last exited.  

This may be in the FAQ (see: www.adahome.com for the FAQ).

Just put the variable at the same or lower scope than the subprogram
that is to use it.  Typically this is at package level.

Ex.1:

procedure P is

    V : Some_Variable_Type ...

    procedure Sub_P is
    ...-- V works as you wish for all invocation of Sub_P
    end Sub_P;
...
end P;


Ex.2:

package P is

    V: Some_Variable_Type ....


  procedure P1 ...

  procedure P2 ...
...
  -- V works as you wish for all invocations of any Px here
  -- (also for any subprograms in the body of P and any child unit
  -- of P or, for that matter, any importer of P (with P...)
end P;

/Jon
-- 
Jon Anthony
Organon Motives, Inc.
Belmont, MA 02178
617.484.3383
jsa@organon.com





^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Static variables?
  1997-03-18  0:00 ` Jon S Anthony
@ 1997-03-18  0:00   ` Samuel Tardieu
  1997-03-18  0:00     ` Tom Moran
  1997-03-19  0:00   ` Robert Dewar
  1 sibling, 1 reply; 10+ messages in thread
From: Samuel Tardieu @ 1997-03-18  0:00 UTC (permalink / raw)



>>>>> "Jon" == Jon S Anthony <jsa@alexandria> writes:

Jon> In article <332D71FF.4773@cae.ca> Viqar Abbasi <viqar@cae.ca>
Jon> writes:
>> Is there a way to declare local variables in ADA subprograms to be
>> STATIC?  That is, they retain the value that they had when the
>> subprogram was last exited.

Jon> Just put the variable at the same or lower scope than the
Jon> subprogram that is to use it.  Typically this is at package
Jon> level.

This is of course the way to do it, but your answer corresponds to the
case of a C toplevel static variable, not to the case of a C static
variable located in a function. In the first case, your variable may
be accessed by several subprograms, in the second one, it can only be
accessed by *one* C function.

This is not possible in Ada to have the equivalent of a C static
variable located in a function, you have to put it at the module
(package) level, let's say in the package body as Jon said.

  Sam
--
Samuel Tardieu -- sam@ada.eu.org




^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Static variables?
  1997-03-18  0:00   ` Samuel Tardieu
@ 1997-03-18  0:00     ` Tom Moran
  0 siblings, 0 replies; 10+ messages in thread
From: Tom Moran @ 1997-03-18  0:00 UTC (permalink / raw)



If the variable should really be private to a single function, like a C
static variable inside a function, how about:

package lots_of_things is
  ...
  procedure p_with_state;
  ...
end lots_of_things;

package body lots_of_things is
  ...
  package state_p is
    procedure actual_p;
  end state_p;
  package body state_p is
    static_variable : integer := 0;
    procedure actual_p is ... -- has access to static_variable
  end state_p;
  ...
  procedure p_with_state is
  begin
    state_p.actual_p;  -- call the real p procedure to do its thing
  end p_with_state;
  ...




^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Static variables?
  1997-03-17  0:00 ` Robert Dewar
@ 1997-03-18  0:00   ` nasser
  0 siblings, 0 replies; 10+ messages in thread
From: nasser @ 1997-03-18  0:00 UTC (permalink / raw)



as Dr Dewar mentioned, package variables retain their values
from the time the package becomes avaliable to the time the
package life ends (usually the end of the program , but not
always the case, example, if the package is declared inside
a block or procedure), may be a picture will help:
 
 
 
                   package A interface
                 +---------------------+
                 | i: integer;   -----------> retain its value also
client <=======> | procedure foo;      |
                 | .......             |
                 +---------------------+               
          
         .............................................
       
                   package A body
                 +---------------------+
                 |j: integer;   --------------> these variables retain
                 |                     |         their values 
                 | procedure foo is    | 
                 |   n: integer;  ------------> variables here are auto
                 |   begin             |        variables, new copies are
                 |     ....            |        created each time foo is called
                 | end foo;            |
                 |                     |
                 | begin               |
                 |   ....    ----------------> this code execute once when
                 | end A;              |       package is first elaborated. 
                 |                     |       use this code to init package
                 +---------------------+       variables.
                                               
 
you can think of variables declared in the package interface as static puplic
in C++ class terminolgy, and variables declared in the body of the package 
but outside the functions and procedure of the package body as static 
private in C++.
 
offcourse it is a good idea to try to avoid using variables in the interface
part of the package.
 
nasser




^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Static variables?
  1997-03-18  0:00 ` Jon S Anthony
  1997-03-18  0:00   ` Samuel Tardieu
@ 1997-03-19  0:00   ` Robert Dewar
  1997-03-25  0:00     ` Richard A. O'Keefe
  1 sibling, 1 reply; 10+ messages in thread
From: Robert Dewar @ 1997-03-19  0:00 UTC (permalink / raw)



Jon said (answering question about static variables)

package P is

    V: Some_Variable_Type ....
    procedure P1;


Robert notes:

This is not good advice, or at least does not answer the question. The
idea of static variables (e.g. in Algol60 or C) is to create a variable
that can only be referenced by the procedure, but which retains its value
from call to call.

You certainly do not map such a facility by putting variables in the package
spec, which can be accessed by clients.

A much closer approximation is to place the variable in the package body,
where it cannot be seen by a client. Note that in Ada 95, the variable
definition can go right next to the body (this is one of the good arguments
for dropping the annoying basic-later ordering restrictions on declarations
in Ada 83).

The closest approximation is

package body P is

     package P1_Package is
        procedure P1_Proc;
     end P1_Package;

     package body P1_Package is
        V : Some_Variable_Type ...
        procedure P1_Proc;
     end P1_Package;

     procedure P1 renames P1_Package.P1_Proc;

     ...


and now the variable V is not directly visible even in the body of package
P, but for most purposes this is probably overkill, since simple naming
conventions and discipline can presumably be trusted at the single package
level, it is clients who must be stopped from fiddling with the variable
directly.

Note that the whole idea of static variables is fundamentally inconsistent
with task safety, since the variable V here is almost certainly going to be
a shared variable which is in danger of generating erroneous behavior
(RM 9.10(11-15)). 

Possible solutions are

  Make V a protected object (i.e. of a protected type), and get and set its
  value with protected calls. This is likely to be very expensive. On bare
  board implementations, protected types can be made quite efficient, but
  when operating over an operating system, protected object semantics are
  heavy, and protected calls are likely to result in multiple kernel calls.

  Make P1 a generic, with the understanding that separate tasks should
  instantiate separate versions, each of which will have its own variable
  V. 

  Give the caller a handle to V, which is then passed as a parameter, with
  a constructor, and the understanding that different tasks do not share the
  same handle (see Ada.Numerics.Discrete_Random for an example of this 
  approach).

  Make V atomic, so that updates are task safe.

Solution 1 (the protected object) will always work, but might be expensive.
Solutions 2-3 are appropriate only if it is OK to have multiple V's (the
random number case is an archetype of this case).

SOlution 4 works only if the operations on V are limited to simple loads
and stores (e.g. a First_Time_In Boolean would work, although you have
to be prepared for race conditoins, so that two tasks could both think
it was the first time in. If you need to do x := x + 1, then the atomic
solution creates additional race conditions.

Note that in solution 1, to avoid race conditions, you need to take 
operations like x := x + 1 inside the protected type.

Making things task safe is not easy at all if you have state of this kind
that must be retained from call to call and if you want efficiency.

Let's consider for example the issue of a memoized Ackerman function.
we really do not want a protected call on every call to Ackerman, since
in typical Unix systems, these calls can be distressingly inefficient,
and one can find that protected calls are comparable to task switching
in overhead. This is a fundamental property of the way that protected
objects were designed (e.g. to respect ceiling priorities accurately)
and it was known during the design that the choices made would result
in a relatively heavy locking mechanism when working over an operating
system (e.g. a protected call cannot use a simple test-and-set lock,
since this would cause possible priority inversions in some unlikely
worst case scenarios).

Back to Ackerman. One approach is to have two (two-D) memory arrays, one
has booleans showing if a value is set, the other has the values. Let's
assume that the values are large composites representing extended precision
values, too big to be atomic.

If a boolean is set, we know we can access the value, without a lock, and
all is safe.

If a boolean is not set, then we take a lock (i.e. we do this in a protected
object) and set the value in place.

This approach means that at least we only pay the price of a lock on the
set, not on every access. Of course if the values to be stored are small
enough to be atomic, then we can just store them and retrieve them directly
(this is a case of solution 4 above).

Code that casually ignores task safety is often very hard to fix up so that
later on it is task safe, without introducing lots of inefficient locks.
This is the problem that is often faced in making C runtime libraries
safe, although in C the problem is made much worse by not having nested
functions, so that one ends up using static variables gratuitously, which
in Ada or Pascal would be up level (task safe) references.

And that by the way is a reminder to C programmers writing in Ada. Do NOT
use global variables gratuitously. For example, suppose you are writing
a scanning package in Ada, where internally there is a scan pointer variable
that is only needed for one outer level client call, but the operation is
complex, and there are many internal procedure calls in the package body.

There are three basic approaches:

1. Pass the scan pointer around everywhere as an in-out parameter, this can
   add a lot of junk to the code.

2. Use a static variable which is set on entry, and then referenced by the
   various procedures (in Ada, the static variable is a package body variable)

3. Make the variable be a local variable of the outer procedure and nest all
   other procedures within this procedure. 

Assuming you are not explicitly using tasking, approach 3 is task safe, but
may not easily occur to C programmers writing in Ada, because they are not
used to writing nested procedures (note the phrasing of the original
question -- when anyone asks "How can I do X in language Y", where X is
a technical term from some other language, alarm bells should go off, because
it is likely that someone is trying to port an unnatural design.

In other words, the best answer to the question "How do I get a static
variable in Ada" is often "Just say NO to static variables".

In general, library level variables in package specs or package bodies
raise task safety issues. A reasonable protocol in an environment where
task safety has to be considered is that EVERY such variable should be
annotated with comments discussing its task safety.







^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Static variables?
  1997-03-19  0:00   ` Robert Dewar
@ 1997-03-25  0:00     ` Richard A. O'Keefe
  1997-03-25  0:00       ` Larry Kilgallen
  0 siblings, 1 reply; 10+ messages in thread
From: Richard A. O'Keefe @ 1997-03-25  0:00 UTC (permalink / raw)



dewar@merv.cs.nyu.edu (Robert Dewar) writes:

>And that by the way is a reminder to C programmers writing in Ada. Do NOT
>use global variables gratuitously.

...

>Assuming you are not explicitly using tasking, approach 3 is task safe, but
>may not easily occur to C programmers writing in Ada, because they are not
>used to writing nested procedures (note the phrasing of the original
>question -- when anyone asks "How can I do X in language Y", where X is
>a technical term from some other language, alarm bells should go off, because
>it is likely that someone is trying to port an unnatural design.

One of the things that has me bewildered and worried is the growing number
of concurrent languages _without_ nested subprograms.  Java is an obvious
example.  Another recent example is Limbo.  The Limbo IPC mechanism is
tranmitting messages over named typed channels.  All processes run in the
same address space.  There are no nested procedures.  Presto no-chango:
it is the _programmer's_ job to ensure that variables are not operated on
in multiple threads.  Ada looks better and better every day.

-- 
Will maintain COBOL for money.
Richard A. O'Keefe; http://www.cs.rmit.edu.au/%7Eok; RMIT Comp.Sci.




^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Static variables?
  1997-03-25  0:00     ` Richard A. O'Keefe
@ 1997-03-25  0:00       ` Larry Kilgallen
  1997-03-27  0:00         ` Robert Dewar
  0 siblings, 1 reply; 10+ messages in thread
From: Larry Kilgallen @ 1997-03-25  0:00 UTC (permalink / raw)



In article <5h8786$oml$1@goanna.cs.rmit.edu.au>, ok@goanna.cs.rmit.edu.au (Richard A. O'Keefe) writes:

> One of the things that has me bewildered and worried is the growing number
> of concurrent languages _without_ nested subprograms.  Java is an obvious
> example.  Another recent example is Limbo.  The Limbo IPC mechanism is
> tranmitting messages over named typed channels.  All processes run in the
> same address space.  There are no nested procedures.  Presto no-chango:
> it is the _programmer's_ job to ensure that variables are not operated on
> in multiple threads.  Ada looks better and better every day.

Is the quality being sought just nested subprograms,
or is uplevel addressing actually required ?  There
are languages which have nested subprograms without
uplevel addressing.

I suppose one can simulate uplevel addressing with lots of
in-out parameters, but for me that moves away from readability.

Larry Kilgallen




^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Static variables?
  1997-03-25  0:00       ` Larry Kilgallen
@ 1997-03-27  0:00         ` Robert Dewar
  0 siblings, 0 replies; 10+ messages in thread
From: Robert Dewar @ 1997-03-27  0:00 UTC (permalink / raw)



Larry said

<<Is the quality being sought just nested subprograms,
or is uplevel addressing actually required ?  There
are languages which have nested subprograms without
uplevel addressing.

I suppose one can simulate uplevel addressing with lots of
in-out parameters, but for me that moves away from readability.>>

Absolutely the issue is uplevel addressing. nested procedures without
uplevel addressing are a rather small feature, they provide a bit of
namespace protection, which can be provided by other means.

The context of the original remark was to do with threaded programs, where
nested procedures and uplevel addressing are an enormous help in writing
thread safe code. Have a look back at the start of the thread, and reread
my comments on the structure of printf for an example.





^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~1997-03-27  0:00 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1997-03-17  0:00 Static variables? Viqar Abbasi
1997-03-17  0:00 ` Robert Dewar
1997-03-18  0:00   ` nasser
1997-03-18  0:00 ` Jon S Anthony
1997-03-18  0:00   ` Samuel Tardieu
1997-03-18  0:00     ` Tom Moran
1997-03-19  0:00   ` Robert Dewar
1997-03-25  0:00     ` Richard A. O'Keefe
1997-03-25  0:00       ` Larry Kilgallen
1997-03-27  0:00         ` Robert Dewar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox