rick@tetrauk.UUCP (Rick Jones) (05/29/90)
I would like to add some thoughts to the recent discussion on the syntax of export declarations in Eiffel. (I have only just come onto the News, hence the apparent lateness of this contribution. I have, however, been doing some fairly intense evaluation of Eiffel 2.2 over the last 6 months). The various suggestions are certainly interesting, and I would generally agree that the language would be more elegant without the export clause. The main point in favour of keeping it seems to be the advantage of grouping the names of all exported features together. Bob Wiener mentioned the importance of source style in declaring all exported features together, and thus all secret features together. How about formalising this in the syntax? To me the name "feature" implies export, so I would suggest something like: feature count: INTEGER ; doit is do end ; -- etc secret state: BOOLEAN ; -- etc end This introduces "secret", already widely used in Eiffel terminology, as a new keyword. For restricted exports, another section could be permitted in the form: feature {ONECLASS, OTHERCLASS} -- etc This would overcome another comment regarding the tedium of having to repeat export restrictions after every affected feature. (In practice, all or most of a class's restricted exports will have the same restrictions.) If you don't want another keyword, "feature" for secret, and "feature export" (or even "feature {ANY}" - think about it!) could be adopted. As for inheriting exports, this is certainly an essential facility, but the implementation of "repeat" in 2.2 is not nice, and gives the impression of being shoved in rather hastily. With or without the export clause, it should definitely be done in the inheritance section, and I would agree with the suggestion of :- inherit export A -- etc. -: as being the cleanest. I would like to suggest a possibly controversial idea on this theme, though: when is there any requirement *not* to inherit a parent's exports? There is no size or performance overhead in exporting features, so the argument is purely a philosophical one, and my reasons go thus: The purpose of having secret features is two-fold a. to hide the implementation of a class, so that a client class *cannot* be written which is dependent on its supplier's implementation, thus allowing implementations to be changed without breaking programs. b. to prevent a client using what is in effect a private subroutine of a supplier class, whose unrestricted use could break the supplier class invariant, etc. If a class inherits features from its parent, and chooses not to export them, they do *not* become inaccessible to clients since an object of the child class can be accessed via a reference of its parent's type (a fundamental concept of OO languages!). Features which are redefined in the child are also still accessible via the parent type due to dynamic binding which (thank goodness) cannot be prevented in Eiffel. If this is viewed in terms of the concepts "inheritance of abstraction" versus "inheritance of implementation", Eiffel *always* implies the former. The inheritance of invariants enforces this even further (redefined routines should also inherit their parent's pre- and post- conditions, but don't - a sore point). Therefore, there seems little reason not to inherit exports, or if you have a reason non-inheritance should be the exception, with inheritance the default. This leads to my suggestion of: inherit A -- exports repeated by default rename foo as bar redefine foo export bar -- exports the renamed feature ; secret B -- exports not repeated export xyz ; The export statement in the position shown (suggested by Steve Tynor) covers two possibilities: With A, renaming and redefining foo means that the new version of foo is the effective final version for this class, with bar being the parent version of foo. Assuming foo is exported by A, the export inheritance means that the name exported here is foo, not bar (without the redefine it would be bar). If bar (i.e. the parent version of foo) also needs to be exported from the child, this must be explicitly stated, and there is nowhere else to do it if we remove the main export clause. With B, we have inhibited automatic export of B's exported features, but we do want to export xyz, so we have to say so. It also allows the child to export one of the parent's features which the parent didn't export, though I think that wanting to do this implies suspect design somewhere. One can take an even more purist line and say that features that the parent didn't export were designed as internal only, and so the child should have no right to export them at all. This includes the inherited foo renamed as bar in the example above, since the redefined foo is the implementation for the child, access to the parent version is an internal convenience for the child class. Secret inheritance may be regarded as superfluous, and if this view is also taken, there is no need for export as even a sub-section of inherit, since all exporting is controlled by the section in which the feature was originally defined. It certainly simplifies the language, though going this far could be guaranteed to break many existing working programs; the compiler would need a compatibility mode as an option (uugh!). The BIG problem in doing this is how to cater for classes which are designed for inheritance, not as suppliers (like the library classes BASIC, MEMORY, EXCEPTIONS, etc). They are written with their features exported, because if they aren't "short" doesn't document them! A class inheriting from one of these almost certainly does *not* want to export these features to its clients. Perhaps the cleanest solution would be to have another section in addition to "feature" and "secret" in which to place features of this sort. They would not be exported, but would be identified by "short" as requiring description, and in slightly different terms from exported features. This would also be a good way to define tricky things like deferred secret functions called from routines in a parent class but resolved only in descendants (like a "match" function where the searching loop is in the parent). I seem to be re-writing the language ... ! But could this stimulate some interesting discussion? I also have some comments on John Potter's query about restricted exports, but this article's long enough already. Watch this space ... -- Rick Jones You gotta stand for something Tetra Ltd. Maidenhead, Berks Or you'll fall for anything rick@tetrauk.uucp (...!ukc!tetrauk.uucp!rick) - John Cougar Mellencamp