[comp.lang.eiffel] eiffel and external c routines

fcaggian@kepler.com (Frank Caggiano) (10/18/90)

I have been trying to access an Eiffel object from a C routine
and am having no luck.  What I need to do is access a fixed list
of intergers from the C routine.  I have tried all the ways I
can think of using the routines shown on pages 220-221
of Eiffel the language.  They don't specifically show
the object being passed in however so is this possible?

Also while I've ben going through this I thought that if I 
created the object in C passed it back to eiffel and then passed
it back to C maybe it would work then. GHowever when I went to write
the C call to eif_create I bummped up afgainst the fact that 
FIXD_LIST is a constrained type.  How do you create a constrained
type in C ?  All I could comme up with was:

	eif_create("fixed_list[integer]",some-number)
but seems a bit far fechted. I haven't had time to try it out.
Anyone have any ideas?

Below is an example of code for my first problem:

The Eiffel part:
class CEIF 

feature

	Create is
		external
			foo: language "C"
		local
			x: FIXED_LIST[INTEGER]
		do
			x.Create(3);
			x.put_i_th(1,1);
			x.put_i_th(2,2);
			x.put_i_th(3,3);
			x.start;
			io.putint(x.item); io.new_line; 
			x.forth;
			io.putint(x.item); io.new_line; 			
			x.forth;
			io.putint(x.item); io.new_line; 			
			x.start;
			foo(x);
		end;
end;


The C part:
#include "/usr/local/Eiffel/files/_eiffel.h"
foo(x)
    OBJPTR x;
{

    int i;
    extern int eif_err;

    for (i = 1; i <= 3; i++) {
	printf("i = %d (%d) {%d} [%d]\n",i,eif_err,eif_attr(x,"count"),
	       eif_attr(x, "item"));
	eif_rout(x,"forth");
    }
}

what prints out (from the C part):
i = 1 (-1) [0] [0]
i = 2 (-1) [0] [0]
i = 3 (-1) [0] [0]

The printout in Eiffel is ok.

-- 
Frank Caggiano                      INTERNET: fcaggian@kepler.com  
Kepler Financial Management, Ltd.       UUCP: ..!uunet!kepler1!fcaggian
100 North Country Rd.                    fax: (516) 751-8678
Sekauket, NY 11733                     voice: (516) 689-6300 

tarvydas@turing.toronto.edu (Paul Tarvydas) (10/18/90)

There's a problem with your C code and with documentation:

	1) My copy of 'Eiffel: The Language' incorrectly documents
	   "eif_rout".  It returns a *pointer* to a routine.  [Also,
	   the names in the C string must be entirely lower case and
	   25 characters or less.] So, after calling "eif_rout", you
	   still have to call the routine, eg. 

	   	(*(eif_rout (obj, "feat"))) (obj);

	   or, more humanely put (and, more efficiently, if you're going
	   to make the call more than once):

	   	ptr = eif_rout (obj, "feat");
		...
		(*ptr) (obj);

	   [Remember that you have to supply the "Current" Eiffel object
	   as the first arg to an Eiffel routine.]

	 2) Your C code is wrong because "item" is a routine, not an
	    attribute (maybe that's why you got the -1 eif_err's).

So, here's your C code:
============================
#include <stdio.h>
#include "/home/Eiffel/files/_eiffel.h"
foo(x)
OBJPTR x;
{
  
  int i;
  extern int eif_err;
  extern ROUT_PTR eif_rout ();
  ROUT_PTR item, forth;

  item = eif_rout (x, "item");
  if (item == NULL) {
    fprintf (stderr, "can't find 'item'\n");
    exit (1);
  }

  forth = eif_rout (x, "forth");
  if (item == NULL) {
    fprintf (stderr, "can't find 'forth'\n");
    exit (1);
  }

  for (i = 1; i <= 3; i++) {
    printf("i = %d (%d) {%d} [%d]\n",
	   i, eif_err,
	   eif_attr (x, "count"),
	   (*item) (x));
    (*forth) (x);
  }
}
==============================

And here's the output:

1
2
3
i = 1 (0) {3} [1]
i = 2 (0) {3} [2]
i = 3 (0) {3} [3]


As to your question about C-creating instances of generic types, why not
write a new class, say "fixed_list_of_integer", then Create it? eg.

	class
	  FIXED_LIST_OF_INTGER
	export
	  repeat FIXED_LIST
	inherit
	  FIXED_LIST [INTEGER]
	    rename
	      Create as flCreate
	feature
	  Create (n : INTEGER) is
	    do
	      flCreate (n);
	    end;
	end;

Paul Tarvydas
tarvydas@tsctrl.uucp
TS Controls
5 Bowness Crt.
Etobicoke, Ontario, Canada
M9B 5Z8
tel. (416)-234-0889, fax. (416)-234-9193

nosmo@eiffel.UUCP (Vince Kraemer) (10/19/90)

If you have been having trouble with the issue of using Eiffel objects
in C code and have access to a fairly good archive of comp.lang.eiffel,
I would suggest (re)reading message <391@eiffel.UUCP>, which covers the
subject and agrees with the implementation of 2.2 (and 2.3). If you
don't, I can post it again or mail it to you (depending on the demand).

Another item covered in the cited article is the use of class MEMORY to
deal with the disposal of externally allocated resources, when an object
is garbage collected.  Well, I hate to say it, but I believed the
documentation in the class and the semantics that were discussed when
this feature was being designed.  In testing this feature, I discovered
that it works, if you respect the following caveats, which are not
documented: 

1. The dispose will only work in DIRECT descendants of MEMORY only.

2. The dispose feature is only called when the routine MEMORY.full_collect is
   called (not MEMORY.collect is called or when the collection is
   triggered automatically).  This does limit the applicability of 
   using dispose or of automatic memory management considerably.

There is a caveat, for those who can still make good use of
dispose, to apply when writing dispose routines:

   DO NOT apply remote notation (dots) to attributes.  There is no order
   implied in the collection of garbage.  This means that it is possible
   that an attribute of an object has been collected before it client.
   Trying to dereference the collected object will raise an exception.

I wish to apologize to all those who may have been mislead by my
previous posting.  I have learned my leason though: test then post.

The following shar file has a system to illustrate the use of
dispose (correctly).

Vince Kraemer
ISE Tech. Support
(technical correspondence to: eiffel@eiffel.com)

----------------------------- sh-archive -------------------------------

# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by geneve!nosmo on Thu Oct 18 17:12:48 PDT 1990
# Contents:  a.e driver.e .eiffel
 
echo x - a.e
sed 's/^@//' > "a.e" <<'@//E*O*F a.e//'
--|---------------------------------------------------------------
--|   Copyright (C) Interactive Software Engineering, Inc.      --
--|    270 Storke Road, Suite 7 Goleta, California 93117        --
--|                   (805) 685-1006                            --
--| All rights reserved. Duplication or distribution prohibited --
--|---------------------------------------------------------------
--| Author: Vincent Kraemer @ Interactive Software Engineering
--| Created: Thu Oct 18 09:26:43 1990

class A export
	
inherit

	MEMORY redefine dispose;
		
feature

	a1, a2, a3, a4: integer;
	
	dispose is
		do
			-- The use of io will be okay since it is shared.
			-- all others you must be careful about.
			io.putstring ("Disposing of an A.");
			io.new_line;
		end;

end -- class A
@//E*O*F a.e//
chmod u=rw,g=rw,o=r a.e
 
echo x - driver.e
sed 's/^@//' > "driver.e" <<'@//E*O*F driver.e//'
class DRIVER export
	
inherit

	MEMORY
	
feature
	
	hold: ARRAY [A];

	Create is
		local
			an_a: A;
			ol, il: integer;
		do
			io.putstring ("Now using manual storage control.");
			io.new_line;
			collection_off;
			from
				ol := 0
			until
				ol = 200
			loop
				io.putstring ("second test: ");
				io.putint (ol);
				io.new_line;
				hold.create (0, 100000);
				from il := 0;
				until il > 100000
				loop
					an_a.create;
					hold.put (an_a, il);
					il := il + 1;
				end;
				ol := ol + 1;
				hold.forget;
				full_collect;
				collection_off;
			end;
		end;
			
end -- class DRIVER
@//E*O*F driver.e//
chmod u=rw,g=rw,o=r driver.e
 
echo x - .eiffel
sed 's/^@//' > ".eiffel" <<'@//E*O*F .eiffel//'
------------ 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: driver
UNIVERSE: /usr/local/Eiffel/library/support
EXTERNAL:
NO_ASSERTION_CHECK (N):
PRECONDITIONS (Y): ALL
ALL_ASSERTIONS (N):
DEBUG (N):
TRACE (N):
OPTIMIZE (N):
GARBAGE_COLLECTION (y)
C_PACKAGE (N):
C_EXTERNAL:
MAKE:
VISIBLE (N):
----------------------------------------------------------------
@//E*O*F .eiffel//
chmod u=rw,g=rw,o=r .eiffel
 
exit 0