Xref: utzoo comp.lang.eiffel:577 comp.object:759 Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!cs.utexas.edu!tut.cis.ohio-state.edu!ucsd!hub!eiffel!bertrand From: bertrand@eiffel.UUCP (Bertrand Meyer) Newsgroups: comp.lang.eiffel,comp.object Subject: Eiffel cleanup #2: Doing away with void references Keywords: Type system, export controls, NONE, ANY, HERE Message-ID: <227@eiffel.UUCP> Date: 17 Jan 90 08:25:32 GMT Organization: Interactive Software Engineering, Santa Barbara CA Lines: 274 A planned change for the handling of ``void'' references in Eiffel ------------------------------------------------------------------ This is the second of a sequence of postings describing the changes planned for version 3 of Eiffel. These are cleanup changes and do not affect anything fundamental. This is particularly true of the change described here, whose concrete effect on the actual form of Eiffel software is extremely small, although its conceptual impact (in terms of elegance of the overall language structure and type system) is significant. I am cross-posting this particular message to comp.object because of its Eiffel-independent components (influence on the type theory of object-oriented programming). Acknowledgments --------------- The key idea for the improvement described here was contributed by John Sarkela, director of training at Interactive Software Engineering. As usual, the rest of the Eiffel group at Interactive provided essential help and feedback. ---------------------------------------------------------------------- |WARNING: The change described here is planned for version 3 of the | |Eiffel environment, for which Interactive will not release a version | |until late 1990. | | | |Any change in the language supported by Interactive's tools | |will be accompanied by CONVERSION TOOLS to translate ``old'' syntax | |into new. Programmers will NOT need to perform any significant work | |to update existing Eiffel software. | | | |This posting is made solely for the purpose of informing the Eiffel | |community about ongoing developments. Although the posting has been | |preceded by careful reflection and internal discussions within | |Interactive, we make no commitment at this point that the features | |described here will actually be included, and, if they are, that | |their final form will be the exact one shown below. | ---------------------------------------------------------------------- Purpose of the change. ---------------------- The purpose of the change is to solve several problems at once through an improved syntax and semantics for what is currently known as ``void references'' in Eiffel. The problems and their solution affect the conceptual cleanliness of the language and its type system more than the specifics of Eiffel programming. Problem 1: In current Eiffel, there are two kinds of values for entities of class types: ``void reference'' or reference to an object. (In contrast, entities of the other kind of type, expanded, have values which are always objects.) The need to precede any semantic discussion by a qualifier of the form ``if the reference is not void, then...'' is a nuisance. Problem 2: If a system attempts to apply a feature to an entity whose value is a void reference, this cannot be executed and triggers an exception. Such a situation is inevitable (it may be the case that in an object-oriented theory of computation the presence of an ``feature application to void reference'' would be the basic undecidable problem); it should, however, be treated in a more general framework, such as type checking. Problem 3: In some special cases, it may be useful to permit routines that are applicable to void references. A typical example is procedure print, in the universal class ANY; this is applicable to objects of any type, so that a.print will print a representable form of a adapted to the type of a. There are good arguments for making such a procedure applicable to void references: if you are adding print instructions to a class for purposes of debugging, you probably want a.print to do nothing, silently, if a is void, rather than produce a run-time exception. Although we have experimented with various techniques for specifying that a routine is applicable to void references, none seems to be really satisfactory. The problem is that Eiffel routines are not just ``pieces of code'' but the implementation of a *contract*, specified by a precondition and a postcondition. The pre- and postconditions become extremely complex to express if you take into account the special treatment for the case when the target is void. Problem 4: Normal feature applications a.f (...) act on the object associated with reference a, and cannot change that reference itself. There are, however, four exceptions: Create, Clone, Forget and Void. Such irregularity is unpleasant. The case of Create and Clone was addressed in a previous posting (which, by oversight, forgot to list Void among the culprits). This leaves Forget, whose effect is to make the target void, and Void, a boolean-valued feature which tells whether the target is void or not. (By default, all entities have a void value on creation.) The universal classes (reminder) -------------------------------- The following is just a reminder which is necessary to understand the remainder of the discussion. The Eiffel class system includes two special classes: ANY and HERE. HERE inherits from ANY, and any programmer-defined class inherits from HERE (without explicit specification by the programmer) ANY contains a few universally useful features: print (mentioned about), io (standard input/output) etc. HERE is empty as delivered, so that it just repeats the features of ANY. Programmers are free to add features (normally routines) to it, however, whereas ANY is meant to be left unchanged. This makes it possible to endow every class written in a certain environment with new universal features local to that environment (a project, a department, a company). The language change ------------------- The structure of the class system is now the following: ANY ^ | | | HERE ^ ^ ^ | | | | | | | | | | | | ............................................................... ............................................................... ............................................................... ............... All other classes .......................... ............................................................... ............................................................... ^ ^ ^ | | | | | | | | | | | | NONE In other words, there is a new class NONE, which (as the picture tries to show within the constraints of vertical-horizontal-only graphics) inherits from every class. Those of you who like lattices and complete partial orders will be happy to see that the multiple inheritance lattice of Eiffel has now at last gained its ``bottom''. (Others should ignore this paragraph.) This means that whenever any Eiffel programmer anywhere in the world writes a new class, he must write to the maintainers of class NONE in sunny Goleta (California) so that we can update its inheritance clause; in so doing we must remove name clashes as necessary. The previous sentence contains two inaccuracies: - We just got our first real rain in more than a year, which is good because we would all have died of thirst if it had not been for the Zinfandel from the Santa Ynez wineries. - You do not really need to tell us about your new classes (although we are always happy to know). The effect is conceptually that of NONE inheriting from everybody else, but it does not have to be that way physically. As alert readers will have guessed, there is no more ``void'' value. Every value of class type, without exception, now refers to an object. What used to be called a void value is now a reference to an instance of class NONE. It is enough to have one instance of this type around during the execution of any Eiffel system since (as will be seen next) almost nothing may be done to it. Indeed, we may consider that one such instance is created at system execution; any entity of class type is initialized to a reference to that object (This specification may be taken verbatim by an implementer of Eiffel; or it may be just used as a metaphor, the implementation being different. As noted below, the current implementation of Eiffel does not need to be changed for the metaphor to hold conceptually.) Class ANY now contains a function null: NONE is once end which returns a reference to the single meaningful instance of NONE. Instead of writing a.Forget, then. you now write (as in Pascal!) a := null The test a.Void may in principle be written a == null but it is better to keep the old form a.void, which is now now a normal feature call to the function void: BOOLEAN is do ... end in class ANY. Note that ``void'' and ``null'' need not be actually implemented as functions. For obvious performance reasons, a smart compiler may (and probably should) recognize the corresponding feature calls and treat them in-line - using exactly the same code as in current Eiffel. Actually, one of the nice aspects of this change is that the current implementation (where void values are references with a special value, such as 0 or -1) remains totally valid. The theory changes, but the practice may remain the same. Only a small syntactical change is needed: replacing calls to Forget by assignments, as indicated above. Obviously, this change will be performed by automatic tools, not by the programmers. There is virtually no change in semantics since almost no operation is exported by NONE, so that a.f will usually be incorrect if a is void. Why ``almost'' and ``usually''? Well, class NONE is not as empty as you may think at first. The theoretical form of that class is class NONE export repeat HERE inherit ... All classes ever written by anyone ... end [Each one among these ``all classes'' inherits from HERE.] For those readers who haven't read ``Eiffel: The Language'', the ``repeat HERE'' clause means that NONE exports everything that its ancestor HERE exports. This includes basic features such as void, print, null, out, io etc. (By the way, it is hardly unlikely that anyone would want to declare an attribute in HERE since every object will carry it. This is not forbidden, but is a big responsibility. In most cases HERE should only contain routines, which do not take up any space in objects, and whose code is removed by the automatic optimizer if not used.) No you see how the problem of routines applicable to void references is addressed: such routines occur rarely enough, and are special enough, that they should be added to your local version of HERE. One of the remarkable aspects of this structure is that the problem of ``feature application to void references'' becomes a special case of type checking! Those readers who remember an earlier, lengthy posting on static type checking in Eiffel will see that the present change puts the whole discussion in a more general perspective. A note on conversion of existing software ----------------------------------------- Conversion of existing Eiffel classes will be straightforward and, as mentioned above, done automatically. (Actually, a simple lexical translator, or even a 3-line sed script could do it.) -- Bertrand Meyer bertrand@eiffel.com