[comp.lang.eiffel] passing address of an eiffel feature

duns1222@w203zrz.zrz.tu-berlin.de (Martin Dunschen) (03/06/91)

Hello everybody,

I have a problem passing the address of an Eiffel feature
to a foreign routine, written in C.

In the case you want to pass the address of a simple feature,
like a real, it seems to be no problem. Also, as given in the
example $EIFFEL/examples/.../callbacks, comming along with version 2.3,
it is possible to pass pointers to eiffel-routines.

But how to pass pointers to complex features, like ARRAY[REAL] ?

The reason, we want to do this, is the reuse of software, written
in FORTRAN77. If you know this language, you can imagine that there
is extensive use of fortran arrays, passed via parameterlists.

Because Eiffel 2.3 does not know external clauses with 
language "Fortran", we use short C procedures, which call the 
Fortran subroutines. The argument passing and all other problems
using C together with Fortran are already solved.

To supply the Fortran subroutine with these arrays, or getting back
the results of a computation on an array, we think about using
the possibility of passing pointers of Eiffel features to foreign
routines, this is descibed very brief in 
"Eiffel: The language (version 2.2)", pages 218, 219.

Perhaps there is a workaround?

Nevertheless I include a few C routines and eiffel-classes,
showing in two examples what I mean.

You cut this file at the indicating lines, put the parts in new
files, named .eiffel, test.e, c_test.c for example 1 in one directory,
and the others, with same names in another directory. Compile the
C-routine in each directory and invoke es. The executable in example
1 does what I expect, example 2 is somehow a clue for me!

Thanks in advance, Martin

+-----------------------------------------------------------------+
| e-mail: dunschen@zrzsp9.fb12.tu-berlin.de                       |
|         dunschen@DB0TUS11.BITNET                                |
|                                                                 |
| voice : +49.+30.31424109                                        |
| fax   : +49.+30.31426883                                        |
+-----------------------------------------------------------------+
CUT HERE ------CUT HERE ------CUT HERE ------CUT HERE ------CUT HERE ------
--
-- Beginning of first example, following files are .eiffel, test.e, c_test.c
--
------------ EIFFEL SYSTEM DESCRIPTION FILE -------------------
--   For simple uses, just replace ``root_class_name'' below
--   by the name of the root class of your system (lower case)
ROOT: test
UNIVERSE: $EIFFEL/library/structures $EIFFEL/library/support
EXTERNAL: c_test.o
NO_ASSERTION_CHECK (N): ALL
PRECONDITIONS (Y): ALL
ALL_ASSERTIONS (N): ALL
DEBUG (N):
TRACE (N):
OPTIMIZE (N): ALL
GARBAGE_COLLECTION (N)
C_PACKAGE (N):
C_EXTERNAL:
MAKE:
VISIBLE (N):
CUT HERE ------CUT HERE ------CUT HERE ------CUT HERE ------CUT HERE ------
--|
--| test.e
--|
class TEST

feature

        value : REAL;

	Create is
            external c_test language "C"
        do
              value := 25.;

              io.putstring (" this is test.e value=");
              io.putreal (value);
              io.putstring ("\n");

              c_test (@value);

              io.putstring (" this is test.e, after c_test value=");
              io.putreal (value);
              io.putstring ("\n");

        end --create

end -- class TEST
CUT HERE ------CUT HERE ------CUT HERE ------CUT HERE ------CUT HERE ------
/* c_test.c */
c_test (parm)
float *parm;
{
	printf ("this is c_test, parm= %f \n", *parm);
        *parm = *parm +25.;
}
CUT HERE ------CUT HERE ------CUT HERE ------CUT HERE ------CUT HERE ------
--
-- Beginning of second example, following files are .eiffel, test.e, c_test.c
--
------------ EIFFEL SYSTEM DESCRIPTION FILE -------------------
--   For simple uses, just replace ``root_class_name'' below
--   by the name of the root class of your system (lower case)
ROOT: test
UNIVERSE: $EIFFEL/library/structures $EIFFEL/library/support
EXTERNAL: c_test.o
NO_ASSERTION_CHECK (N): ALL
PRECONDITIONS (Y): ALL
ALL_ASSERTIONS (N): ALL
DEBUG (N):
TRACE (N):
OPTIMIZE (N): ALL
GARBAGE_COLLECTION (N)
C_PACKAGE (N):
C_EXTERNAL:
MAKE:
VISIBLE (N):
CUT HERE ------CUT HERE ------CUT HERE ------CUT HERE ------CUT HERE ------
class TEST

feature

        list : ARRAY[REAL];

	Create is
            external c_test language "C"
        do
              list.create(0,2);
              list.put (  10.,0);
              list.put (  20.,1);
              list.put (  30.,2);

              io.putstring ("test, before c_test:\n");
              io.putreal (list.item (0));
              io.putstring ("\n");
              io.putreal (list.item (1));
              io.putstring ("\n");
              io.putreal (list.item (2));
              io.putstring ("\n");

              c_test (@list);

              io.putstring ("test, after c_test:\n");
              io.putreal (list.item (0));
              io.putstring ("\n");
              io.putreal (list.item (1));
              io.putstring ("\n");
              io.putreal (list.item (2));
              io.putstring ("\n");
        end --create

end -- class TEST
CUT HERE ------CUT HERE ------CUT HERE ------CUT HERE ------CUT HERE ------
c_test (list)
float *list;
{
	printf ("this is c_test, list(0)= %f \n", list[0]);
	printf ("                list(1)= %f \n", list[1]);
	printf ("                list(2)= %f \n", list[2]);
        list[0] = list [1] + list [2];
}

duns1222@w203zrz.zrz.tu-berlin.de (Martin Dunschen) (03/07/91)

This posting is especially to Greg Economides of Biosystems
Modelling Group at Texas A&M University, e-mail greg@carnivore.tamu.edu

BUT everybody interested, feel free to read on, perhaps read first my
posting from the day before, same subject!

Hi Greg,
I tried to send you a mail, but it turned out that your configuration
is not ready for receiving mail, so I try this way.


thank you for your help regarding our problems passing eiffel features
to foreign routines. I understand the main principle now.

You call the "methods", e. g. the features `item' and `put', from
within the C routine. For this you have to find them, depending on
the object, to which these features belong. In our example we
refer to the features `item' and `put' via the ROUT_PTR eif_rout.
We store the pointers to these features on the variables `put_ptr'
and `item_ptr' for further use.
Ok, so far so good, but I tried your code-examples, with a few minor
changes, and they didn't work. The following questions arose:

1. Do you pass an_array as it is or as @an_array ?

2. How to declare an_array in c_func, as Object or OBJPTR ?

3. How do I know the number/types of parameters to item_ptr and put_ptr?
   Are they according to the syntax in an eiffel-program ?

4. How to declare myvar, as float, or as a pointer to something else ?

Again, I include eiffel and C code, what I got from you with some
changes. (Our C compiler seems not ANSI standardized !)

Excuse me, when I bother you again, but what can I do?

Bye, Martin
CUT HERE ------ CUT HERE ------ CUT HERE ------ CUT HERE ------ CUT HERE ------ 
class WHATEVER 
 
feature
 
	an_array: ARRAY[REAL];
 
	Create is
	   external c_func language "C"
	do
		an_array.Create ( 0, 2);
                an_array.put    (10.,0);
                an_array.put    (20.,1);
                an_array.put    (30.,2);
                output ("before calling c_func:",
                                  an_array.item(0),
                                  an_array.item(1),
                                  an_array.item(2));

		c_func(@an_array);
             -- c_func(an_array);

                output ("after calling c_func:",
                                  an_array.item(0),
                                  an_array.item(1),
                                  an_array.item(2));
	end; -- a_feature
       
        output (str: STRING; r1, r2, r3: REAL) is
        do
                io.putstring (str);
                io.putreal (r1);
                io.putstring (" ");
                io.putreal (r2);
                io.putstring (" ");
                io.putreal (r3);
                io.putstring ("\n")
        end -- output

end; -- class WHATEVER
CUT HERE ------ CUT HERE ------ CUT HERE ------ CUT HERE ------ CUT HERE ------ 
#include "/path/to/Eiffel/files/_eiffel.h"

void c_func (array_ptr)
OBJPTR array_ptr;
/* Object array_ptr */
{
extern ROUT_PTR eif_rout;

/* in the example /path/to/eiffel/examples/eiffel-c/callbacks
   the previous declaration looks like
   extern ROUT_PTR (*eif_rout)();
*/

ROUT_PTR put_ptr, item_ptr;

float myvar; /* is this correct? I'm not shure */

 
/* assigning the eiffel routines to variables `put_ptr' and `item_ptr'
   is useful if these eiffel functions will be used more than once.
   otherwise a one-time call can be made like this:
	(*(eif_rout(array_ptr,"item")))(array_ptr, 3)
	                  arguments to `item' -----^      */

printf ("in c_func, before assigning pointers to eif_rout's\n");
put_ptr = eif_rout(array_ptr, "put");
item_ptr = eif_rout(array_ptr, "item");
printf ("in c_func, after assigning pointers to eif_rout's\n");
 
/* Now, to use these pointers to eiffel functions */
 
printf ("in c_func, before calling item \n");

/* myvar = *(eif_rout(array_ptr,"item"))(array_ptr, 3); */

myvar = (*item_ptr)(array_ptr,3);

printf ("in c_func, after calling item, myvar=%f\n", myvar);

/* maybe you'd make a fortran call here which would change the value of
   myvar....  and then you might want to put it back into the array */
 
myvar = myvar * 2.; /* just an example to change something */

printf ("in c_func, before calling put, myvar=%f\n", myvar);

/* (*(eif_rout(array_ptr,"item")))(array_ptr,myvar, 3); */

(*put_ptr)(array_ptr,myvar,3);

printf ("in c_func, after calling put, myvar=%f\n", myvar);
 
}