[comp.lang.eiffel] Calling eiffel-routines from C ?

jos@cs.vu.nl (Jos Warmer) (03/09/89)

Many window-system, written and callable from C, have the following
architecture.

You initialise your application and install some callback-functions
and tell on which event they shoul be called.

Then you give control to the window-system which takes over
everything and calls one of the installed C callback-functions when
an event happens. E.g. XtMainLoop in Xt toolkit, window_main_loop in SunView.

Using this from eiffel poses the problem that the C window-system takes
over and needs to call eiffel-routines (not C), otherwise eiffel loses
control altogether.

Is it possible in eiffel to make C functions call eiffel-routines.
I know it is in standalone C packages, but that's not what I need.

Or does anyone know another solution ?

============================================================================
                                 Jos Warmer
				 jos@cs.vu.nl
				 ...uunet!mcvax!cs.vu.nl!jos
============================================================================

bertrand@eiffel.UUCP (Bertrand Meyer) (03/11/89)

From article <2135@vlot.cs.vu.nl>, jos@cs.vu.nl (Jos Warmer):
> Many window-system, written and callable from C, have the following
> architecture.
> 
> You initialise your application and install some callback-functions
> and tell on which event they shoul be called.
> 
> Then you give control to the window-system which takes over
> everything and calls one of the installed C callback-functions when
> an event happens. E.g. XtMainLoop in Xt toolkit, window_main_loop in SunView.
> 
> Using this from eiffel poses the problem that the C window-system takes
> over and needs to call eiffel-routines (not C), otherwise eiffel loses
> control altogether.
> 
> Is it possible in eiffel to make C functions call eiffel-routines.
> I know it is in standalone C packages, but that's not what I need.

This answer has two parts: immediate solution and more long-term
reflection.

I am cross-posting it to comp.lang.c++ because difference between
the Eiffel approach and what I assume would be
done in a C extension may be of interest to readers of
this newsgroup.

1 - IMMEDIATE SOLUTION
----------------------

	Three C functions are available for calling
Eiffel routines from C. Actually the ability to call a routine
on an object is not enough: you must also be able to create this object
from C, and to access an attribute (not just a routine) of this object.
The following three functions are available for this purpose:

		eif_create (class_name, arg1, arg2, ...)
				Create an Eiffel object of type class_name;
				arg1, arg2, ... are the arguments (at most eight)
				to the Create procedure of class_name, if any.
				The function returns a pointer to the object.

		eif_rout (object_ref, routine_name, arg1, arg2, ..)
				Apply the Eiffel routine routine_name to the
				Eiffel object referred to by object_ref, with
				arguments arg1, arg2, ... (at most eight).
				If the routine is a function, eif_rout will return
				its result.
				
				Reference object_ref must refer to an Eiffel object;
				it will normally have been obtained by eif_create.
				String routine_name must be
				the name of a routine in the class of which the object is
				an instance.

		eif_attr (object_ref, attr_name)

				Value of attribute attr_name for the Eiffel object
				referred to by object_ref.

				Reference object_ref must refer to an Eiffel object;
				it will normally have been obtained by eif_create.
				String attr_name must be
				the name of a routine in the class of which the object is
				an instance.

	These two functions will be part of release 2.2. The first two
were actually present in release 2.1, but not documented. To install them
right away, you need a couple of C files which we will gladly send to any
Eiffel user who requests them. Just send a message to

		source@eiffel.com

with subject header ``Access to Eiffel from C''. No message text is
necessary. We'll mail back the files (one copy has been sent to Jos
already). If you don't need the facilities right away, they will be part
of 2.2 anyway.

	On a different but related issue: if you are using Eiffel with
Suntools or Sunview, you may run into problems because the Sunview Notifier
insists on handling all external events, including signals. This defeats
the Eiffel exception handling mechanism. In version 2.2 special support is
provided to solve this problem (by ensuring that the Notifier passes on
any event which is not meant for it).

2 - THE REAL ISSUE
------------------

	The above will be useful in practice for Eiffel users who need to
interface with existing C packages of the type described by Jos. Typical
examples are the Notifier under Suntools/Sunview, and similar facilities under
X windows.

	This immediate usefulness should not, however, lead us to forget that
the underlying problem is much better solved by object-oriented
techniques. The general C trick that is used in the cases mentioned is
the following:

	- Define a default way of handling a certain event. This is described
		by a certain function; more precisely, by a variable,
		say event_handler, whose value is a pointer to the
		appropriate function.

	- When the event occurs, call that function.

	- Enable a programmer to override the default handling
		by assigning to variable event_handler a pointer to
		a different function.

This works but it is really a form of low-level hacking. In particular,
no static check is possible to guarantee that all overriding functions
will have the correct signature (type of arguments and results).

The desired effect - providing a default behavior, and enabling
programmers to explicitly override this default if they so desire -
is precisely what is made possible in object-oriented programming by
multiple inheritance, redefinition and dynamic binding.

The Eiffel technique is straightforward: define the default behavior
in a class, say BASE, where the various event handlers are routines.
Any class that needs these facilities will inherit from BASE.
(This is where multiple inheritance is essential: you may need
to combine more than one default behaviors, for example one
for a window system and one for a database).
If you want to override the default behavior in a specific
case, just redefine the corresponding routine in the appropriate class.
Static typing ensures that the consistency of the new argument types
with the original will be checked. Dynamic binding ensures that the
event will be handled adequately (by the default routine or by the
redefined version, depending on the context).

This is exactly the way we implement the X interface in the Eiffel
Graphics Library, so as to hide from programmers all the low-level C
coding tricks. When interfacing with existing C packages, of course,
programmers must live with the techniques enforced by these packages, in
which case the answer given at the beginning of this message is the
appropriate one.

-- Bertrand Meyer
bertrand@eiffel.com