Dee(ID:2917/dee001)


for John Dee, Elizabthan mathematician and magician

Peter Grogano Concordia (Canada) 1991 Dee is a statically typed, dynamically bound object oriented programming language Amongst other object oriented languges, it is most similar to Eiffel and Sather. It is, however, simpler than these languages.

"In fact, the primary objective in the design of Dee was that programs written in it should be easy to maintain. A second objective was to keep the language simple"


People:
Structures:
References:
  • Grogono, P. The book of Dee. Technical Report OOP-90-3. Department of Computer Science. Concordia University. February 1990 view details
  • Grogono, Peter "Issues in the Design of an Object Oriented Programming Language" Structured Programming, January 1991 view details Abstract: The object oriented paradigm, which advocates bottom-up program development, appears at first sight to run counter to the classical, top-down approach of structured programming. The deep requirement of structured programming, however, is that programming should be based on well-defined abstractions with clear meaning rather than on incidental characteristics of computing machinery. This requirement can be met by object oriented programming and, in fact, object oriented programs may have better structure than programs obtained by functional decomposition.

    The definitions of the basic components of object oriented programming, object, class, and inheritance, are still sufficiently fluid to provide many choices for the designer of an object oriented language. Full support of objects in a typed language requires a number of features, including classes, inheritance, genericity. renaming, and redefinition. Although each of these features is simple in itself, interactions between features can become complex. For example, renaming and redefinition may interact in unexpected ways. In this paper, we show that appropriate design choices can yield a language that fulfills the promise of object oriented programming without sacrificing the requirements of structured programming.
    Extract: Introduction
    Introduction
    The goal of structured programming is to find abstractions that enable us to build correct and efficient computer programs. The idea that an object is a useful abstraction emerged in the design of SIMULA 67 [1], inspired Smalltalk [2]. and recently has achieved widespread popularity. Despite its antiquity, the notion of an object is still fluid and the subject of vigorous debate.
    Structured programming is strictly unnecessary because we could, in principle, write all our programs in machine language. Thus the goal of structured programming cannot be expressed in precise terms such as correctness or completeness. Nevertheless, the central objective of structured programming is clear: it is to find abstractions that express computations. The most useful abstractions yield programs which are easy to read, easy to reason about, and efficient to execute.
    We can trace the evolution of object oriented programming by considering the roles of scope and extent in the history of programming languages. The physical distance between the definition and use of an identifier has a significant effect on the readability of a program. The scope of an identifier is the region of program text in which the identifier may legitimately be used. The extent of a variable is the period of time for which it exists during execution. We can classify programming languages in terms of their treatment of scope and extent. In the earliest languages, all variables had global scope and infinite extent. FORTRAN introduced limited scopes. Algol introduced limited extent, described by nested blocks and implemented by stack allocation. Although stack allocation had the important consequence of supporting recursion, the close coupling of scope and extent was occasionally too restrictive. The own variable of Algol 60 was an early but ultimately unsuccessful attempt to overcome the restrictions, but it led to the concepts of class and object of SIMULA 67.
    A class defines a scope within which the attributes of an object are declared. Some of these attributes are visible outside the class and provide the means of manipulating the object. A class provides a means of instantiating new instances of the class which are called objects.
    Although the definitions of "class" and "module" differ between programming languages, we can say broadly that a class is a kind of module. The difference between modules and classes lies in the nature of the entities which may be exported. In most modular languages, a module may export arbitrary entities, including types, constants, variables, and procedures. In most object oriented languages, a class can export only procedures which perform operations on instances of the class. The difference leads directly to one of the major issues of structured programming. Is the greater generality of modules necessary? Do the restrictions on classes unduly limit the expressiveness of the language?
    Two other research topics of the seventies contributed to the development of classes and objects. Information hiding [3] demonstrates the importance of the module interface as a contract between client and supplier. The development of abstract data types [4] demonstrates the importance and usefulness of separating specification and implementation.
    The philosopher's stone of programming is reusable code. All programmers have experienced deja vu as they write yet another slight variation on a table search. The key to reuse is abstraction and parametrization [5]. The object oriented paradigm provides both. Most object oriented languages support inheritance, a mechanism which enables the common features of a group of classes to be abstracted into a parent class. Some object oriented languages also support parameterized classes, which enable one class to do the work of many.
    In this paper, we describe the design of a simple object oriented language [6]. The language is called "Dee". after the British mathematician and philosopher John Dee, 1527-1608. Dee is a strongly typed, object oriented language with facilities for developing and maintaining programs [7]. In fact, the primary objective in the design of Dee was that programs written in it should be easy to maintain. A second objective was to keep the language simple.
    In Section 2, we discuss the objectives of the language design exercise and the criteria we imposed on the new language. In Section 3. we give a brief description of Dee, highlighting its unusual features. In Section 4, the major section of the paper, we describe some of the problems which arose during the design of Dee and our solutions to them. In Section 5, we discuss some aspects of object oriented programming style which go beyond most discussions of this topic in recent publications. Finally, in Section 6, we discuss the lessons we have learned from this exercise in language design.
    Extract: Objectives and Criteria
    Objectives and Criteria
    A useful program may have a lifespan of many years. During that time, it will be maintained, probably by many different programmers. Three kinds of maintenance are recognized in software engineering: perfective, adaptive, and corrective [8. Chapter 27]. Perfective maintenance improves the program without changing its functionality. Adaptive maintenance responds to changing requirements and compensates for changes in the environment in which the program is used. Corrective maintenance diagnoses and rectifies
    previously undiscovered errors.
    The most difficult task confronting a maintenance programmer is to understand existing code. In many cases, the code was written by a programmer who is no longer available for consultation. The programming language and the tools that support it must be designed to assist the maintenance programmer as much as possible.
    Consideration of the primary objective of maintainability led to six design principles for Dee. The first of these principles was that information should not be duplicated. Redundancy may be useful, but duplication is not. The second principle was that all information related to a program entity should be in one place. Both of these principles contribute directly to maintainability. They have several immediate consequences: for instance, Dee programmers do not write separate files for specifications and implementations; there is no need for separate documentation files; and there are no import or export lists in class declarations.
    The third principle is that the programmer should not have to provide information that the compiler can easily infer and display. For example. Dee programmers do not have to write the names of attributes inherited from another class. The compiler can infer the names and make them available when they are needed by programmers. Conversely, programmers should provide information that the compiler cannot easily infer, such as whether a method is intended to be used as a constructor.
    The fourth principle is that the semantic analysis performed by the compiler should not be complicated. For example, an elaborate system of automatic cercions requires the compiler to analyse many different cases. This principle may seem surprising at first sight. The tendency has been for compilers to become more complex as languages have become more advanced.
    The meaning of a program should be evident from its text. If it is difficult for a compiler to understand a program, it will be difficult for people also. We use the phrase "semantic analysis" in the strict sense of checking that the program is semantically correct. The compiler of an object oriented language may need to perform extensive analysis to obtain efficient code, but we consider this to be part of optimization, code generation, or linking, rather than of semantic analysis.
    The fifth principle is that a language which is intended for the development of production quality software should be strongly typed. A program with type declarations is easier to read and modify than an untyped program. We do not require that a type-correct program should never raise an exception at run-time, but we do require that it should never fail in an unanticipated way.
    Strong typing is motivated by the principle that semantic analysis should be simple, but there are other reasons for desiring it. While it is true that, if a language is suitably designed, the compiler can infer types in the absence of type declarations [9, 10], and that type inference is convenient for interactive and prototyping languages [11], untyped programs are not suitable for production software. The benefit from automatic type inference is that programs are slightly shorter. The loss is that programs are harder to understand and compile. With a little extra effort from the programmer, the tasks of both the compiler and the maintenance programmers can be simplified.
    The sixth and final principle is that a language should support the chosen programming paradigm completely and consistently. For example, in some languages, the assignment statement x := y may have value or reference semantics depending on the types of x and y. This kind of inconsistency draws the attention of programmers to the underlying implementation and weakens the coherence of their conceptual model of the language. Many programmers are reluctant to give up inconsistencies to which they have become accustomed because they feel a need for "flexibility."
    Programmers want flexibility and low-level features for two reasons. The first is that they need to write low-level, machine-oriented programs. This requirement can be accomodated by a relatively small number of carefully designed features, as Wirth demonstrated in the design of Modula-2 [12]. The second reason is that programmers want their programs to be "efficient." Almost any program will be efficient if it meets three conditions: (1) the compiler implements the basic operations of the language efficiently; (2) the programmer chooses appropriate algorithms; and (3) the programmer ensures that the most frequently executed code segments (usually the inner loops) are identified and carefully coded. If these conditions are satisfied, the additional improvement that can be obtained by writing tricky code is usually small and is often outweighed by the extra work of debugging and maintaining the program [13].
    The ideal programming language would be both simple and efficient. There are situations in which the desire for simplicity and efficiency work together. Some of the most interesting issues in language design arise, however, when it is necessary to establish a balance between simplicity and efficiency. As an example, consider the representation of objects in an object oriented language. There is a choice between storing the object itself or a reference to it. The language designer's choices include the following.
    ?  Represent all objects by references, as in LISP and its descendants. This strategy is simple to implement but potentially inefficient.
    ?  Represent objects of a few basic classes by values and all others by references, as in early versions of Eiffel [14],  This strategy is likely to lead to semantic inconsistencies of the kind already described.
    ?  Give the programmer full control over the representation, as in CH?h [15]. This strategey complicates both the language definition and the programmer's task.
    ?  Let the compiler choose the appropriate representation. This strategy is likely to complicate the compiler, perhaps to the point of infeasibility.
    In cases such as these, our goal was to keep the syntax and semantics of the language simple and to be faithful to the object oriented paradigm. We accepted that the implementation, at least in early versions, would have inefficiences, but it is usually easier to improve an implementation than it is to improve a language design.
  • Grogono, Peter "PC-Dee: A Reference Manual" Concordia February 1994 view details
  • Grogono, Peter "PC-Dee: Syntax and Semantics" Concordia February 1994 view details
    Resources