[Mo89]) is a Common Lisp's entry into the object-oriented programming word, which initiated different approaches in additional investigations. On the other hand, ...
A PERSPECTIVE ON COMBINING DIFFERENT PROGRAMMING PARADIGMS Ljubomir Jerinic Institute of Mathematics University of Novi Sad Trg D. Obradovica 4 21000 Novi Sad, Yugoslavia ABSTRACT The motivation and the basic issues for designing the programming system - ELa, that allowed combination of different programming paradigms is presented in the part one of this paper. In the ELa system distinct styles of programming (functional, logic and object-oriented) are enabled. The system is currently under development at the Institute of Mathematics in Novi Sad. In this paper we describe the problem definition of a multiprogramming system, and the current state of realization of that programming system. In the part two we will illustrate the ELa system that permit the combination of the functional, the logical and the object-oriented paradigm of programming.
1.
INTRODUCTION
Investigation in the field of combining different programming paradigms or programming styles in one environment or in one system is almost old as appearing the distinct philosophy of solving problems by the aid of computers. Nowadays, there are several programming styles and appropriate programming languages in use in computing activity and practice. Any of these programming styles has its own advantages and disadvantages. For some problems or classes of problems one style is better than the others, but there is no perfect programming style or programming language appropriate for different use. Almost all modern programming languages merge a few different programming paradigms, but in other hand all of them are at least the programming languages of only one programming style, i.e., one philosophy of solving some problem. Besides that, programming languages have distinct syntax and specific data structures on which they operated. However, a language that supports a paradigm well is often hard to distinguish from the paradigm itself in practice.
2.
MULTIPARADIGM IN PROGRAMMING LANGUAGES
A programming paradigm [Am92] is a collection of conceptual patterns that together develop the design process and definitively decide the way of solving some problems and program's structure. The control how we think about and formulate solutions, and even whether we arrive at solutions at all, directly arbitrate is some program valid or not. Existing of different style of programming is the result of distinct and disparate problem spaces in which solution of some problem will be found. That problem spaces require diverse solutions, and even in a single area contrasting techniques are often helpful. According that, there exist many separate styles of programming which served for solving different subclasses from the space of all
problems. Every programming paradigm gives in his definitional domain the possibility of resolving some problem on the efficient and simple way, describing the solutions as the computer program. In the current state of the art of computer programming a dozen programming paradigms is presented, and we will now slightly describe some of them. The imperative paradigm is directly mapping of the Von Neumann architectures of the computer emphasizes variables and values, i.e., the memory cells. On the other hand functional style of programming has the root from the mathematical theories of recursive functions and λ-calculus. Functions are first class subjects, i.e., they could be parameters of the other functions and they could be the result of evaluation. The applicative nature of that kind of programming manifests in manipulation on values, rather than on assignable cells - memory addresses. The logic paradigm is based on a procedural interpretation of the first-order predicate calculus and Horn-clause logic with equality. The manipulation in it is based on unification of the relationship between objects and values. The object-oriented programming is based on the idea and realization of the concept of abstract data types. The object operators and the manipulations on the objects are based on the behavior and the communication between them, rather than operating on objects themselves. The need for some multiparadigm environments is almost old as the appearance of different programming paradigms. The advantages of that system are obvious. That system offers the possibility for operating with most appropriate features of distinct styles in some single application. On the other side, they are often too complicated and too big. In the last decade the programming language designers set many efforts in combining and merging some of different paradigms in one. This theoretical and practical work takes many directions. One is in designing some new programming languages. The others try to realize the environment for simultaneous work with several different languages, i.e., paradigms. For example, logic programming shares many origins with functional programming, including the applicative nature of functional programming, i.e., manipulation on values instead with memory cells, the recursion, chances for improvement for parallelism and so on. Of course there are many differences between these two programming paradigms like radically different variable treatments, ability of higher order programs and fundamental support for nondeterministic executions. Therefore, all of that was a good base for different attempts in combinations of those paradigms or appropriate programming languages. Robinson and Sibert's LOGLISP was the first attempt in this view that proved to be quite successful as well as instructive. In the late eighty there were many distinct attempts in combining the functional and logic style of programming in either design a new language or adding the new abilities in existing one [DeG86] such as QUTE, FUNLOG, LEAF, APPLOG, EQLOG, TABLOG, Uniform and FRESH. The system CLOS (Common Lisp Object System [Mo89]) is a Common Lisp's entry into the object-oriented programming word, which initiated different approaches in additional investigations. On the other hand, the programming language LEDA [Bu91] is a strongly typed, compiled language that tries to combine features of the imperative (that portion is derived from the Algol tradition of languages like Pascal and Modula) and logical or relation-oriented styles of programming. The programming language C++ [St86] includes the imperative and object-oriented programming paradigm, and there is some attempt in combining functional and imperative style in [Oz91]. The development of truly multiparadigm languages opens new possibilities for the computing community. They let us more easily compare solutions to problems presented in various styles and the programmers could better understand the importance and appropriate use of techniques from different paradigms while still working in only a single language. Software development in a multiparadigm way allows that different parts of complex software systems
might be design with different techniques that are the most suitable for that portion of the problem. For example, in the field of Intelligent Tutors Systems, the knowledge base of semantics nets might be best described using functional style, the graphical interfaces for a lesson design in the object-oriented manner and the student's module and a phase of learning could be nicely managed in relational or logic technique of programming. In a compiler design for some language, for another example, the parser could be realized using logical expression, the symbol table as an object and the transformations on an intermediate form might be best described in a functional style. Clearly, all these styles are useful at the different times and for different tasks, and in any sufficiently complex problems a combination of approaches may be called for. Thus, the field of multiparadigm system or multiparadigm language research has developed. But, combining languages are more than just connecting syntaxes. New language must have internal consistency, i.e., the parts must work easily together, as well as accomplishing the advantages of all styles individually. First, the imperative, object-oriented, functional and logical paradigms will be briefly described.
3.
IMPERATIVE PARADIGM
The imperative paradigm is characterized with the Von Neumann model of the computer that consists of a large memory and a processor unit. Although von Neumann machines underlie the implementation of almost all paradigms, the imperative style of programming uses this computer model for conceptualizing solutions. The other paradigms, by contrast, use conceptual models removed from this implementation model. Step-by-step computational sequences characterize this style, and during computations the processor repeatedly modified the space of the variables, i.e., the abstraction of memory cells. The program written in the imperative style consists of precisely described sequences of manipulations on memory cells. Programming in this style is dominated by deciding what data values will be required for computation, representing these values by associating them with variables and deriving some step-by-step sequences of transformations to those variables so that final state represents the correct result values. Many programming languages support this model. Some of them include extensions that support other paradigms to varying degrees. They support only simple statements and appropriate operators for manipulating data, such as assignment statement for modify memory, conditional and unconditional branching, repeating statements, adding operators and so on. Today's imperative languages contain a variety of borrowed mechanisms or appropriated idea from another style such as non side-effecting functions, recursion, and dynamic allocation of pointers. But, they nevertheless remain conceptually dominated by the machine model. However it is also truly fact that almost all modern programming languages have something from imperative style. For example many dialects of programming languages LISP often include imperative constructs such as multiple assignment that destroy the non-side-effecting nature of the functional paradigm and force further sequencing constructions into the construction of programs. Also, the programming language Prolog that is typically represents of the logic programming paradigm includes the cut operator for controlling the backtracking mechanism that is also imported from imperative style.
4.
OBJECT-ORIENTED PARADIGM
As we said, in the imperative paradigm, the conceptual model is a single memory space into which abstract data values are represented. On that data space one or more procedures,
which represents operations, are applied. Each procedure deals directly with stored representation. The object-oriented paradigm [We90] holds much of the Von Neumann computer, but, on the contrary, procedures operate on abstract values, called objects, rather than on memorized representation. As a result, this paradigm requires the capabilities of defining new objects composed of existing objects in a hierarchical order, and of manipulating them by defined procedures called methods. Object-oriented paradigm first defines suitable objects for the problem, and then uses these objects to describe step-by-step operational sequences. The process of solving problems in object-oriented style realizes the top-down technique of modeling the world. As we said, in the imperative paradigm, the conceptual model is a single memory space into which abstract data values are represented. On that data space one or more procedures, which represents operations, are applied. Each procedure deals directly with stored representation. The object-oriented paradigm [We90] holds much of the imperative style, but, on the contrary, procedures operate on abstract values, called objects, rather than on memorized representation. As a result, this paradigm requires the capabilities of defining new objects composed of existing objects in a hierarchical order, and of manipulating them by defined procedures called methods. Object-oriented paradigm first defines suitable objects for the problem solving, then uses these objects to describe step-by-step operational sequences. The process of solving problems in object-oriented style realizes the top-down technique of modeling the world. The manipulation of abstract values instead on concrete representation, requires respect for encapsulated state of objects. That means that the right of objects to define their concrete representations and to do all manipulations upon such representation. This is accomplished by sending messages that describe the desired manipulations and leaving it to the objects to act on them. The object defined via other sub-objects, took operational sequences to alter their internal representations. Such sequences include sending messages to their sub-objects. This process proceeds until at some level in that hierarchy the objects and the methods defined on them are primitive. Inheritance, single or multiple, are the second characteristics associated with object-oriented style of programming. It is based on the idea of object classes and hierarchy. A class is the definition of an object from which instances of the definition are created. Inheritance allows rapid definition of a new object class from the concrete representation and the methods of an existing class. The new class includes all of the methods defined on the inherited representation, and any new concrete representations. Also, new or revised methods added to it. The third characteristics of the object-oriented paradigm are message-passing. The objects could be considered as active entities that send messages to one another. To support this model, procedures must be polymorphic, i.e., multiply defined with particular invocations determined by examining the types of the parameter objects. While the message-passing mechanism of the object-oriented style is computational equivalent to the procedure call approach of the extended imperative paradigm (with a possibility to have a complex data in the procedure or the function definition), it leads to a very different way of looking at problem solutions. There is a conceptual difference between searching through some procedures with same names for a match of the particular parameter types, and in sending messages to a particular object that knows only one such method. In the former case of procedure calls the main program controls all the computations, while in the message-passing mechanism each object has full responsibility for correct handling requests made directly to it.
5.
FUNCTIONAL PARADIGM
The functional programming style and relevant programming languages trace their origins to the λ-calculus, recursion equation systems and combinatory logic. We could say that in the functional paradigm [He80, Tu82] the computational model is based on mathematical model of functional compositions. In this model, the result of one computation is input to the next, and so on until some composition yields the desired result. There is no concept of a memory location assigned or modified. Instead of that, there are only intermediate values, which are the results of prior evaluations and the inputs to succeeding computations. There no for command, and all functions are referential transparently. The functional style of programming [Hu89] involves the idea of functions as first-class objects, i.e., the ability of high-order functions. This means that functions can be treated as data, passed as parameters, constructed and returned as values, and composed with other forms of data. There is two ways of the functions' specifications: operationally, i.e., with some control sequencing which is the part of some functional language, and mathematical or definitional without any of controlling statements. With the operational style, the programmers are responsible for the complete sequencing of instructions, including the proper end of the evaluations. By contrast, programming in the definitional functional style provides for termination without requiring explicit control sequencing. In the operation style the conceptual model for problem solving is a construction in which a sequence of steps that will use functional composition to compute the desired result is described. On the other hand, in the definitional model we approach the problem as a collection of disjoint transformations that, taken collectively, define a computational function.
6.
LOGICAL PARADIGM
The logical programming paradigm [Ko79a, Ko79b] is based on a procedural interpretation of the first order predicate calculus. Programming in that style supposes that a set of known facts and a set of rules that allow deduction of other facts are written. Thus, logic programming from the programmer's viewpoint is a matter of correctly declaring all required facts, rules and relevant relations between objects needed for solving some problem. Most of the logic programming languages known today have been based on Horn clauses, a subset of first order predicate calculus. The clause notation of predicate logic combines variables, constants, and expressions to represent conditional propositions. Horn clauses are a restricted form of predicate logic with exactly one conclusion in any clause. A solution of some problem in the logic style is found if a suitable set of rules and substitutions exists such that applying the substitutions to the rules produces a set of grounded rules, i.e., a set with no free variables. A process known as unification develops substitutions for free variables. However, there is no similarly deterministic algorithm for selecting rules, which leads to different implementations that could be very inefficient. Although the Prolog language [Cl81] has become synonymous for logic programming, the specific problem solving strategy realized within Prolog and several other features, distinguish Prolog from the original idea of logic programming. While its pure logic features provide the advantages of the logic style of programming, Prolog can be used in an entirely different way that look like as the imperative paradigm (for example the cut mechanism that control the backtracking technique of programming). The logic paradigm is intended for general purpose programming. Pseudo-definitional logic is used for production programming in industry, where it is very well suited to certain types of problems. These include backtracking search problems that may require multiple
solutions, problems that are naturally represented in terms of production rules (such as natural language translation), and executable specifications for rapid prototyping.
7.
THE MULTIPARADIGM SYSTEM ELa
The programming system ELa Fig. 1 consists of the integrated user interface, editor, compiler and linker. The system is realized on the programming language C++ for the IBM PC compatible computers. It consists of the features imported from the object-oriented style represented in C++ programming language [St86], the functional paradigm illustrated in a subset of A_LispKit Lisp programming language [Je92] and the logic style depicted in a subset of standard Prolog [Cl81]. The user interface is organized like standard menu systems in the window like Figure 1 applications. The screen management, the editor and the whole menu system are implemented with the assistance of well-known libraries for window maintenance, controlling the mouse etc. The programming in the system ELa consists of writing the program in C++, or a subset of A_LispKit Lisp, or in a subset of standard Prolog programming language, Fig. 2. For our work, we take the approach to combine functional and logic programming with object-oriented style by adding the functional and logic capabilities into the object-oriented framework. We started with an object-oriented framework provided by C++ because of its efficiency and compiled time checking. In the first Figure 2
part of our investigation we realized the A_LispKit Lisp language [Je92] which is the improved version of the LispKit Lisp programming language P. Henderson [He80, He83].
Figure 3
The actual process of translation of some A_LispKit Lisp program is done in two phases (Fig. 3). During the first phase of the translation the part of the program written in A_LispKit Lisp language is decoded in the A_SECD machine instruction, and during the second phase, the C++ codes are generated according to the information stored in the symbol and operation table. Some Prolog program is translated analogously. The execution of some multiparadigm program is illustrated in Fig. 4.
8.
CONCLUSION
In this paper we presented the system ELa in which the possibilities of combining functional and logical styles of programming in object-oriented environment are allowed. The combination of these different paradigms shows a great potential to support the representation of domain knowledge into declarative data types and make them reusable in different context. However, much work needs to be done. The system is currently under the development, and in the further work the subset of the Prolog Language and the Warren Prolog machine will be incorporating in the system ELa, on the same manner as we do with A_LispKit Lisp and the A_SECD machine. Then we must realize the vertical communication between data and different programming paradigms. Figure 4
REFERENCES [Am92]
[Bu91] [Cl81] [DeG86] [He80] [He83]
[Hu89]
[Je92]
Ambler, A. L., Burnett M. M., Zimmerman B. A., Operational versus definitional: a perspective on programming paradigms, Computer, IEEE, September 1992. Budd, T. A., Blending imperative and relational programming, IEEE Software, January 1991, pp 58-65. Closkin, W. F., Mellish, C. S., Programming in Prolog, Springer-Verlag, 1981. DeGroot, D., Logic programming, Functions, Relations, and Equations, Prentice-Hall, New Jersy, 1986. Henderson, P. Functional programming - Applications and Implementations, Prentice-Hall, London, 1980. Henderson P., Jones, G. A., Jones, S. B., LispKit Manual, Technical Monograph PRG-32(1), Vol. I and II, Oxford University Computing Laboratory, Oxford, 1983. Hudak, P., Conception, Evaluation, and Application of Functional Programming Languages, ACM Computing Surveys, Vol. 21, No3, September 1989., Pp. 359-411. Jerinic, Lj., Implementation of the Translator Lisp-like Programming Language Using Attribute Grammars, Master Thesis, University of Novi Sad, 1992, (in Serbian).
[Ko79a] [Ko79b] [Mo89]
[Oz91] [Ro82]
[St86] [Tu82]
[We90]
Kowalski, R. A., Logic for Problem Solving, North Holland Publishing Co., 1979. Kowalski, R. A., Algorithm = Logic + Control, Comm. ACM, Vol. 22, No7, July 1979, pp.424-436. Moon, D. A., The Common Lisp Object-Oriented Programming Language Standard, in Kim, W., Lochovsky, F. H., Eds., Object-Oriented Concepts, Databases and Applications, Addison-Wesley, Reading, MA, 1989., Pp. 49-78. Ozick, D. N., A Lisp-Style Library for C, Dr. Dobb's Journal, August 1991, pp. 36-48. Robinson, J. A., Sibert, E. E., LOGLISP: motivation, design and implementation, in Clark, K. L., Tarnlund, S. A., Eds., Logic Programming, Academic Press, 1982, pp 299-314. Stroustrup, B., The C++ Programming Language, Addison-Wesley, Reading, MA, 1986. Turner, A. D., Recursion Equations as a Programming Language, in Darlington, P., Henderson, P., Turner D., Eds., Functional Programming and its Applications (Advanced Course), Cambridge University Press, 1982. Wegner, P., Concepts and Paradigms of Object-Oriented Programming, ACM OOPS Messenger, Vol. I, No1, August 1990, pp. 7-87.