bertrand@eiffel.UUCP (Bertrand Meyer) (09/10/89)
This is posted on behalf of Bruno Borghi, who seems to have trouble posting directly. (I have had no other involvement with this message.) -- Bertrand Meyer bertrand@eiffel.com Abstract This (rather long) contribution proposes a new construct to facilitate the declaration and the use of external routines and external variables. Although this article may seem theoretic, its motivations are purely practical. I could have mailed it directly to Dr. Meyer, but I think that this subject is of interest for every people who try to interface C packages with Eiffel. It would be useful if people having interfaced C packages with Eiffel were willing to share their experience over the net. I. External routine declaration ------------------------------- An Eiffel routine that needs one ore more routines written in other languages must list them in an external clause. This kind of declaration is *local* to the routine and is similar to the local clause which declares local variables. There is no way, as far as I know, to make a *global* declaration of an external routine, i.e., available for every routine in a class. However, under some circumstances, this may be useful. (1) When the same external routine is used in more than one routine of a class, in Eiffel 2.1, it must appear in an external clause for each routine where it is used. The drawbacks are: - it defeats the "no code duplication" rule, which I regard as an essential rule for software quality; it encourages the "cut and paste" style rather than factorization. - it allows the declaration of the same external routine with different identifiers in different routines of the class (it *is* local). This is inconsistent with the fact that in a class an Eiffel feature has only one legal identifier. (2) When the same external routine is used in routines in more than one class, in Eiffel 2.1, it must appear in an external clause for each routine where it is used and for each class. This problem appears when interfacing large C packages with Eiffel to encapsulate them. Examples are graphic packages, In that case, I would like a mechanism similar to the C construct: #include "package.h" In Eiffel, the inherit clause gives us this mechanism, but one cannot easily build a class declaring C bindings. II. A new construct: Foreign routine ------------------------------------ To solve this problem, I propose an addition to Eiffel syntax for routine declarations. I name it the "foreign routine" to distinguish from the "external clause". The syntax could be a mixing between an external clause and a constant declaration ("foreign" is a reserved word, "name" is optional, "language" is mandatory, as in the external clause): c_sqrt(x:REAL):REAL is foreign name "c_sqrt" language "C"; An equivalent declaration is possible with the present Eiffel syntax, but is rather clumsy: c_sqrt(x:REAL):REAL is external dummy(x:REAL):REAL name "c_sqrt" language "C"; do Result := dummy(x) end; The "foreign routine" construct would suppress an useless indirection and would be then more efficient, without the need of a sophisticated postprocessor for optimization. III. Generalization: foreign feature ------------------------------------ The "foreign routine" type of construct is not useful only for routines. This mechanism may be a good one to handle external variables, for which there is no provision in Eiffel 2.1. (To keep an Eiffel flavour, I shall use the term of "external attribute" in place of "external variable") Suppose you interface a package where there are some global variables (global variables are ugly, but they do exist in some commercially available C packages). For each global variable, you must write a lot of code if you read/write access to it. As an example, let us consider a variable declared in C as int mode; To access it, you have to write in Eiffel: get_mode: INTEGER is external c_get_mode: INTEGER language "C" do Result:=c_get_mode end; set_mode(m: INTEGER) is external c_set_mode(m: INTEGER) language "C" do c_set_mode(m) end; You have to write some C as well: extern int mode; int c_get_mode() { return(mode); } void c_set_mode(m) int m; { mode = m; } This is a lot of code. It is not very interesting to type in, and thus it is error prone. Generalizing the "foreign routine" construct, one can imagine a "foreign feature" construct which handles attributes. With this construct, you just need a single line to declare a foreign attribute in a class; there is no more need for additionnal C code. That gives: mode: INTEGER is foreign name "mode" language "C"; and that's all. There is a problem: if we use the syntax of "foreign feature" for "foreign features" as above, then there is an ambiguity between a foreign attribute and a foreign function that takes no argument. To remove this ambiguity, the construct has to be redesigned. We can add a "type-of-feature" keyword to the construct: mode: INTEGER is foreign attribute name "mode" language "C"; c_sqrt: INTEGER is foreign routine name "sqrt" language "C"; The construct is longer, but still simpler than what we have today. We can then just drop the word "foreign"; as the word "language" remains mandatory, it is still clear (but is it clear enough?) that the attribute or the routine is external: mode: INTEGER is attribute name "mode" language "C"; c_sqrt: INTEGER is routine name "sqrt" language "C"; IV. Conclusion -------------- Some points may be discussed, especially for attributes. For instance, one can imagine "readonly" foreign attributes (that are different from "constant" attributes). In fact, this is rather related to the question of declaring attributes of a class readonly for its clients. It is a more general functionality which is not available in Eiffel. I am not sure it is necessary. The syntax for "foreign features" that I propose is just an example to illustrate what I mean. I do *not* mean that this is the syntax that should be actually retained. The "foreign feature" construct may lead to some holes in the typechecking protection. In fact, this holes were already present in the former constructs, because they are inherent to C: interfacing with C is always a risk. So, the "foreign feature" - is not more dangerous than an "external clause" - reduces dramatically the amount of code to type in, without loss of clarity - extends to attributes - and so spares the programmer the bother of cumbersome C coding and of switching from Eiffel world to C world - allows for the design of C-binding classes in similar way as constant classes V. About the author ------------------- Bruno BORGHI E-mail: bborghi@bebop.gipsi.fr Address: METASOFT, 13 rue Duhamel,35000 Rennes,FRANCE Phone: +33 - 99 31 25 88