comp.lang.ada
 help / color / mirror / Atom feed
* Newbie question: Implementing a callback mechanism with Ada 83
@ 2007-02-10 19:38 benibilme
  2007-02-10 20:40 ` Dmitry A. Kazakov
  2007-02-11  2:46 ` Jeffrey R. Carter
  0 siblings, 2 replies; 6+ messages in thread
From: benibilme @ 2007-02-10 19:38 UTC (permalink / raw)


Hello,

I need to develop an Ada application which must conform to Ada83. It
will be part of legacy system. I am very much new in Ada. The
application I have to develop is very much event driven. As an old
time C programmer I wanted to implement an event handling module which
you can subscribe callback functions and trigger the events when
necessary and unfortunately I have realized that Ada 83 does not
support pointer to subprograms. I have read about generics with which
defining subprograms as parameters of subprograms seems possible. On
the other hand, I could not figure out how to do it.

I simply want to store function pointers to some data structure for
some certain events and call them with dynamic data when the event is
triggered.

How can I do it in Ada 83 without the support of pointers to
subprograms. It is clear how to do this Ada95 as there is a direct
support for pointer to subprograms.

Any help is much appreciated.




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

* Re: Newbie question: Implementing a callback mechanism with Ada 83
  2007-02-10 19:38 Newbie question: Implementing a callback mechanism with Ada 83 benibilme
@ 2007-02-10 20:40 ` Dmitry A. Kazakov
  2007-02-11  2:46 ` Jeffrey R. Carter
  1 sibling, 0 replies; 6+ messages in thread
From: Dmitry A. Kazakov @ 2007-02-10 20:40 UTC (permalink / raw)


On 10 Feb 2007 11:38:19 -0800, benibilme@gmail.com wrote:

> I need to develop an Ada application which must conform to Ada83. It
> will be part of legacy system. I am very much new in Ada. The
> application I have to develop is very much event driven. As an old
> time C programmer I wanted to implement an event handling module which
> you can subscribe callback functions and trigger the events when
> necessary and unfortunately I have realized that Ada 83 does not
> support pointer to subprograms. I have read about generics with which
> defining subprograms as parameters of subprograms seems possible. On
> the other hand, I could not figure out how to do it.
> 
> I simply want to store function pointers to some data structure for
> some certain events and call them with dynamic data when the event is
> triggered.
> 
> How can I do it in Ada 83 without the support of pointers to
> subprograms. It is clear how to do this Ada95 as there is a direct
> support for pointer to subprograms.
> 
> Any help is much appreciated.

I remember that once I used access-to-task to emulate access-to-subprogram.
You can make handlers tasks and serve events in rendezvous.

Another [tedious] possibility could be a proxy subprogram:

type Call_Back_Id is (Foo_Id, Bar_Id, ...);

procedure Call_Back (Id : Call_Back_Id, <parameters>) is
begin
   case Id is
      when Foo_Id => Foo (<parameters>);
      when Bar_Id => Bar  (<parameters>);
      ...
   end case;
end Call_Back;

In the data structure you store Id.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



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

* Re: Newbie question: Implementing a callback mechanism with Ada 83
  2007-02-10 19:38 Newbie question: Implementing a callback mechanism with Ada 83 benibilme
  2007-02-10 20:40 ` Dmitry A. Kazakov
@ 2007-02-11  2:46 ` Jeffrey R. Carter
  2007-02-11 21:40   ` benibilme
  1 sibling, 1 reply; 6+ messages in thread
From: Jeffrey R. Carter @ 2007-02-11  2:46 UTC (permalink / raw)


benibilme@gmail.com wrote:
> 
> I need to develop an Ada application which must conform to Ada83. It
> will be part of legacy system. I am very much new in Ada. The
> application I have to develop is very much event driven. As an old
> time C programmer I wanted to implement an event handling module which
> you can subscribe callback functions and trigger the events when
> necessary and unfortunately I have realized that Ada 83 does not
> support pointer to subprograms. I have read about generics with which
> defining subprograms as parameters of subprograms seems possible. On
> the other hand, I could not figure out how to do it.

Why do you want to register callbacks for the events? Does the 
processing for a given event change during execution?

If not, there's no need for callbacks. The handling for a given event 
can know what subprogram to call.

If they do, you no doubt have a fixed set of subprograms that can be 
needed for a given event, under a fixed set of conditions. You could 
have the handling for a given event test the condition and call the 
appropriate subprogram for the current condition.

If you have a need to decouple the detection/generation of events from 
their handling, then the event package can add the events to a queue as 
they're detected, and the handling package can remove them from the 
queue and call the appropriate handling operation, which can test the 
condition and call the appropriate subprogram. If your system is 
concurrent, the queue can allow the caller to block when the queue is 
empty. This is often preferable to polling.

If none of these will work, then I don't understand enough to make a 
meaningful comment. More detail from you might help alleviate that.

-- 
Jeff Carter
"C's solution to this [variable-sized array parameters] has real 
problems, and people who are complaining about safety definitely have a 
point."
Dennis Ritchie
25



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

* Re: Newbie question: Implementing a callback mechanism with Ada 83
  2007-02-11  2:46 ` Jeffrey R. Carter
@ 2007-02-11 21:40   ` benibilme
  2007-02-12  5:03     ` Jeffrey R. Carter
  2007-02-12 19:32     ` Adam Beneschan
  0 siblings, 2 replies; 6+ messages in thread
From: benibilme @ 2007-02-11 21:40 UTC (permalink / raw)


First of all, thank you all for the responses.

What I wanted to achieve is to decouple the packages which are
responsible for the handling of specific events. The initialization of
each specific package would register for the events that it cares
about and only become dependent to the event manager package. Event
manager package would provide the interface for registering callbacks
and the static data for the events, firing an event and removing a
registration etc. A package that monitors a state or an event fires a
defined event in the event manager package with the dynamic data and
event manager module would call successively the registered callbacks
in the different packages which are interested in the event. That was
my intention. As a matter of fact that is a classic solution for event
driven programs that I often use when I code with C. It adds one level
of indirection and breaks the explicit coupling between the event
generators and handlers. It is just a simple publish and subscribe
paradigm. I present a very quick implementation of this module in C
below. I wanted to implement this module in Ada 83 which I am failed
to do.

#include	<stdio.h>
#include	<malloc.h>

typedef enum
{
	ev_start,
	ev_stop,
	ev_error,
	ev_LAST

} Event_Id;

typedef	void	(Event_Handler) (Event_Id id, void *event_data, void
*user_data);

typedef	struct
{
	Event_Handler		*handler;
	void			*user_data;
}
Event_Handler_Info;


typedef struct
{
	short			 nr_of_handlers;
	Event_Handler_Info	*handler_info;
}
Event_Binding;


static	boolean		active;
static	Event_Binding	events [ev_LAST];


void
Event_Handler_Create (void)
{
   Event_Id		 id;
   Event_Binding	*binding;

   binding = &events [0];

   for (id = 0, binding = events; id < ev_LAST; id++, binding++)
   {
      binding -> nr_of_handlers = 0;
   }

   active = false;
}


void
Register_For_Event (Event_Id id, void *user_data, Event_Handler
handler)
{
   Event_Handler_Info	*p, *q, *r;
   int			 i;

   if (handler != NULL)
   {
      Remove_Event_Handler (id, handler);
      p = (Event_Handler_Info *) malloc ((events [id].nr_of_handlers +
1) * sizeof (Event_Handler_Info));
      r = q = events [id].handler_info;
      events [id].handler_info = p;

      for (i = 0; i < events [id].nr_of_handlers; i++)
      {
	 *p++ = *q++;
      }

      p -> handler = handler;
      p -> user_data = user_data;
      events [id].nr_of_handlers++;

      if (r != NULL)
      {
	 free (r);
      }
   }
   else
   {

   }

}  /*  end of Install_Event_Handler  */


void
Deregister_For_Event (Event_Id id, Event_Handler handler)
{
	Event_Handler_Info	*handler_info;
	int			 nr_of_handlers;
	int			 i;
	boolean		 found;

	if (handler != NULL)
	{
		i = 0;
		found = false;
		nr_of_handlers = events [id].nr_of_handlers;
		handler_info = events [id].handler_info;

		while (i < nr_of_handlers && !found)
		{
			if (handler_info -> handler == handler)
			{
				found = true;
			}
			else
			{
				handler_info++;
				i++;
			}
		}

		if (found)
		{
			handler_info -> handler   = events [id].handler_info
[nr_of_handlers].handler;
			handler_info -> user_data = events [id].handler_info
[nr_of_handlers].user_data;
			events [id].nr_of_handlers--;
		}
	}
	else
	{

	}
}


void
Fire_Event (Event_Id id, void *event_data)
{
   Event_Handler_Info	*handler_info;
   int			 nr_of_handlers;
   int			 i;

   nr_of_handlers = events [id].nr_of_handlers;
   handler_info   = events [id].handler_info;

   for (i = 0; i < nr_of_handlers; i++)
   {
      (handler_info -> handler) (id, event_data, handler_info ->
user_data);
      handler_info++;
   }
}  /*  end of Post_Event  */

Of course I can solve my problem without this kind of capability. It
will be brute force solution and according to me  an ugly solution.
For example when an event occurs, the module that detected the event
has to call the subprograms in different packages that are interested
in the event. The packages will be tightly coupled to each other.  The
package that triggers the event has to know the packages and the
subprograms that interested in the event. I can see the Ada 83
reasoning. Yes, the code will be more readable maybe and statically
provable but very very verbose and inflexible. At least with my little
Ada knowledge, that is what I can foresee right now.

The code has to be single threaded. It is a requirement.

By the way, a friend of mine whose is more experienced in Ada send me
this mail which I wanted to share with you.

===========================================================

"I can't claim to be an expert at Ada programming, and I usually use
Ada95, so I may suggest a solution that is cannot be implemented in
Ada83, but I have a few suggestions that you could try.

1. The solution to having no access-to-subprogram type in Ada83 is
usually passing the address of the function around and then in Ada a
function can be declared to 'use' that address as it's own like so:

procedure Foo;

procedure Install_Handler ( Event : Event_Type; Event_Handler :
System.Address ) is
begin
  Event_Array(Event_Type) := Event_Handler;
end Install_Handler;

procedure Call_Handler ( Event : Event_Type ) is
  procedure Temp;
  for Temp use at Event_Array(Event);
begin
  Temp;
end Call_Handler;

-- using the procedure
Install_Handler(Event_One, Foo'Address);


2. It is not unusual with an Ada program for the low level OS routines
to be implemented in C/C++ or Assembly.  Then you could import the C
functions (such as the ones you attached).  This is not due to Ada not
being able to implement low-level routines, it is usually used when
you have existing code, or an OS, that works well and you are used to
using it.

The first step would be to define the procedures in Ada, and then
declare them to be imported from C.  Then it is necessary to define
the types used in the imported subprograms with the correct data size
(8 bits, 16 bits, etc.), and then the correct values (for the
enumerations) so that the data passed from the Ada code matches the C
code exactly.  This last step is very important because by default
most Ada compilers will try to use the most efficient representation
for data types as possible, and this will usually cause problems when
moving data between Ada and another language.  The "Interfaces"
standard library has useful C-specific data types, although I cannot
remember if that package was new in Ada95 or not.  The solution in
this case for passing the procedure address around is to use a generic
32-bit value instead of the System.Address type, and then when calling
the C functions cast the System'Address value of the procedure (that
is gathered from the Function'Address attribute), into the 32-bit
value using a generic standard function called Unchecked_Conversion;

  -- The procedures in Ada
  procedure Event_Handler_Create;
  procedure Post_Event ( ID : Event_Data; Interfaces.Unsigned_32 );
  procedure Install_Event_Handler ( ID : Event_ID; User_Data :
Interfaces.Unsigned_32 ;
                                                   Handler :
Interfaces.Unsigned_32 );
  procedure Remove_Event_Handler ( ID : Event_ID; Handler :
Interfaces.Unsigned_32 );

  -- The importation of the procedures from C
  -- C is the language the function is declared in, the second
paramter is the Ada procedure name, and the third
  -- parameter is what the name of the C function is.
  pragma Import(C, Event_Handler_Create, "Event_Handler_Create");
  pragma Import(C, Post_Event, "Post_Event");
  pragma Import(C, Install_Event_Handler, "Install_Event_Handler");
  pragma Import(C, Remove_Event_Handler, "Remove_Event_Handler");

  type Event_ID is ( ev_start, ev_stop, ev_error, ev_LAST );
  for Event_ID use ( ev_start => 0, ev_stop => 1, ev_error => 2,
ev_LAST => 3);
  for Event_ID'Size use 8;

  -- Global conversion functions
  with System;
  with Unchecked_Conversion;
  function To_Unsigned_32 is new Unchecked_Conversion
( System.Address, Interfaces.Unsigned_32 );
  function To_Address is new Unchecked_Conversion
( Interfaces.Unsigned_32, System.Address );
...
  -- event specific data
  procedure My_Handler ( ID : Event_ID; Event_Data :
Interfaces.Unsigned_32;
                                      User_Data :
Interfaces.Unsigned_32 ) is
    Data : Integer;
    for Data use at To_Address(Event_Data);
  begin
    -- do stuff
  end My_Handler;

  Data : Integer := 5;
...
  -- installing the event
  Install_Event_Handler ( ID => ev_start, User_Data =>
To_Unsigned_32(Data'Address),
                                    Handler =>
To_Unsigned_32(My_Handler'Address) );

Hopefully between those examples you can figure out what you would
like to do.  Essentially, when you are working with low-level code the
use of the Unchecked_Conversion generic function, and the
System.Address type are the biggest tools to remember.  And when
interfacing with other lanugages the following representation clauses
are your friend:

for X'Size use ...
for X use ( A => 1...)
for X use at ...  -- In Ada95 this would be "for X'Address use ..."

I hope that helps!"

===============================================================================








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

* Re: Newbie question: Implementing a callback mechanism with Ada 83
  2007-02-11 21:40   ` benibilme
@ 2007-02-12  5:03     ` Jeffrey R. Carter
  2007-02-12 19:32     ` Adam Beneschan
  1 sibling, 0 replies; 6+ messages in thread
From: Jeffrey R. Carter @ 2007-02-12  5:03 UTC (permalink / raw)


benibilme@gmail.com wrote:
> 
> What I wanted to achieve is to decouple the packages which are
> responsible for the handling of specific events. The initialization of
> each specific package would register for the events that it cares
> about and only become dependent to the event manager package. Event
> manager package would provide the interface for registering callbacks
> and the static data for the events, firing an event and removing a
> registration etc. A package that monitors a state or an event fires a
> defined event in the event manager package with the dynamic data and
> event manager module would call successively the registered callbacks
> in the different packages which are interested in the event. That was
> my intention. As a matter of fact that is a classic solution for event
> driven programs that I often use when I code with C. It adds one level
> of indirection and breaks the explicit coupling between the event
> generators and handlers. It is just a simple publish and subscribe
> paradigm. I present a very quick implementation of this module in C
> below. I wanted to implement this module in Ada 83 which I am failed
> to do.

What you're describing here is more an implementation than a description 
of what you have to do. But to my mind, what you achieve through such an 
approach is not a reduction in coupling, but an increase. The events and 
their handling subprograms must be coupled in such situations. However, 
it is structural coupling to have package A call subprograms in package 
B; it is control coupling to have package B give package A data 
(subprogram access values) that determine what actions package B takes.

> Of course I can solve my problem without this kind of capability. It
> will be brute force solution and according to me  an ugly solution.
> For example when an event occurs, the module that detected the event
> has to call the subprograms in different packages that are interested
> in the event. The packages will be tightly coupled to each other.  The
> package that triggers the event has to know the packages and the
> subprograms that interested in the event. I can see the Ada 83
> reasoning. Yes, the code will be more readable maybe and statically
> provable but very very verbose and inflexible. At least with my little
> Ada knowledge, that is what I can foresee right now.

I'm not prepared right now to wade through a bunch of C code for c.l.a. 
Besides, I'm not interested in how you would do something in C, but more 
in what you're trying to accomplish, so I can comment on something I do 
know, which is a good way to implement that in Ada. My personal bias is 
to avoid the use of access types and values whenever possible, and to 
hide them when not.

What you describe here is a static relationship between events and their 
handling subprograms, and then you say that a static solution to this 
static problem is something you consider "ugly". To my mind, a dynamic 
solution to a static problem is unnecessary complexity; it violates the 
KISS principle and is ugly.

Further, you think the static solution will be easier to read and more 
likely to be correct, but would prefer a less readable solution that is 
more likely to be incorrect. I find that incomprehensible.

SW engineering emphasizes ease of reading over ease of writing, and Ada, 
a language for SW engineering, explicitly adopts this attitude. 
"Verbose" is not a bad word among the SW engineers here.

Changing the action in response to an event in the static version 
involves looking at the code for the event and changing the subprogram 
that is called. In the callback case, it involves finding code not 
obviously related to the code for the event and changing the subprogram 
that is registered. The flexibility seems similar; the ease of making 
the change seems greater in the static case.

It's possible I've missed something since I haven't studied your C code 
in any detail.

> 1. The solution to having no access-to-subprogram type in Ada83 is
> usually passing the address of the function around and then in Ada a
> function can be declared to 'use' that address as it's own like so:

This is not something I would recommend, especially if it adds 
complexity to an otherwise simple problem.

-- 
Jeff Carter
"Now look, Col. Batguano, if that really is your name."
Dr. Strangelove
31



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

* Re: Newbie question: Implementing a callback mechanism with Ada 83
  2007-02-11 21:40   ` benibilme
  2007-02-12  5:03     ` Jeffrey R. Carter
@ 2007-02-12 19:32     ` Adam Beneschan
  1 sibling, 0 replies; 6+ messages in thread
From: Adam Beneschan @ 2007-02-12 19:32 UTC (permalink / raw)


On Feb 11, 1:40 pm, "benibi...@gmail.com" <benibi...@gmail.com> wrote:

> By the way, a friend of mine whose is more experienced in Ada send me
> this mail which I wanted to share with you.
>
> ===========================================================
>
> "I can't claim to be an expert at Ada programming, and I usually use
> Ada95, so I may suggest a solution that is cannot be implemented in
> Ada83, but I have a few suggestions that you could try.
>
> 1. The solution to having no access-to-subprogram type in Ada83 is
> usually passing the address of the function around and then in Ada a
> function can be declared to 'use' that address as it's own like so:
>
> procedure Foo;
>
> procedure Install_Handler ( Event : Event_Type; Event_Handler :
> System.Address ) is
> begin
>   Event_Array(Event_Type) := Event_Handler;
> end Install_Handler;
>
> procedure Call_Handler ( Event : Event_Type ) is
>   procedure Temp;
>   for Temp use at Event_Array(Event);
> begin
>   Temp;
> end Call_Handler;

This may or may not work; as far as I know, it's going to depend on
your particular compiler vendor.  You might need to add an Interface
pragma, which may be called something different in different Ada
implementations (this was replaced by the Import pragma in Ada 95):

procedure Call_Handler (Event : Event_Type) is
   procedure Temp;
   pragma Interface (Ada, Temp);
   for Temp use at Event_Array(Event);
begin ...

If you just use the "use at", an Ada compiler *should* complain that
there's no body for Temp---the existence of a "for ... use at" isn't
supposed to be enough to tell the compiler that Temp's body will exist
somewhere else.  The Interface pragma should tell the compiler not to
expect a body.  However, this is a non-standard feature so there's no
telling what compilers may or may not allow that they technically
shouldn't have.

Basically, you'll probably have to check your compiler implementation
documentation or contact them and ask.  Or you can just experiment to
see if you can get the compiler to do what you want.

If it were me, I'd try to find out why Ada 83 is such a hard-and-fast
requirement---there isn't much downside to switching to Ada 95, as far
as I can tell, unless you're on one of those obsolete machines for
which the manufacturer never bothered to upgrade their Ada compiler to
Ada 95.

                              -- Adam




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

end of thread, other threads:[~2007-02-12 19:32 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-02-10 19:38 Newbie question: Implementing a callback mechanism with Ada 83 benibilme
2007-02-10 20:40 ` Dmitry A. Kazakov
2007-02-11  2:46 ` Jeffrey R. Carter
2007-02-11 21:40   ` benibilme
2007-02-12  5:03     ` Jeffrey R. Carter
2007-02-12 19:32     ` Adam Beneschan

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