
Reflections on Standard ML David B. MacQueen AT&T Bell Laboratories Murray Hill NJ 07974 Abstract. Standard ML is one of a number of new programming languages developed in the 1980s that are seen as suitable vehicles for serious systems and applications programming. It offers an excellent ratio of expressiveness to language complexity, and provides competitive efficiency. Because of its type and module system, Standard ML manages to combine safety, security, and robustness with much of the flexibility of dynamically typed languages like Lisp. It is also has the most well-developed scientific foundation of any major language. Here I review the strengths and weaknesses of Standard ML and describe some of what we have learned through the design, implementation, and use of the language. 1 Introduction The goal of programming language design is to maximize expressiveness while min- imizing conceptual complexity, within the constraint that the language must have an efficient implementation. If a language is to be suitable for large-scale, serious programming (i.e., implementing software that will have users and will therefore have to be robust and maintainable), then it must provide security and facilities for organizing large programs. These are some of the desiderata that guided the design of Standard ML. This paper presents my personal views about language design and the lessons we have learned from the design and implementation of Standard ML. As the field of programming language design matures, it is essential that a more scientific approach should come into play. The history of ML provides an example of how theoretical insights and practical programming requirements can be successfully synthesized. The first section summarizes some of the strengths of Standard ML. We then pro- ceed to some remarks on the process of language design in general and on the design of Standard ML in particular. Next comes a review of some particular lessons learned from the experience of implementing and using Standard ML. Section 5 illustrates the continuing language research activity associated with ML by describing a number of experimental language extensions. These efforts can be seen as exploring options for the next generation of ML-like languages. Finally I discuss the relation between ML and object-oriented programming and finish with some projections about the future development of Standard ML and its successors. I will not review the history of ML here, since that topic is well covered in Appendix E of the Definition of Standard ML ([35]) and in Robin Milner's Turing award interview ([17]). I will also assume some familiarity with ML and refer the reader to John Ophel's paper in this volume ([37]) for an overview of the language, and to Larry Paulson's book ([38]) for a more extensive introduction. I will often use the shorter name \ML," which may refer either to Standard ML in particular or to the generic family of ML languages according to the context. 2 Why Standard ML Works Here is an enumeration of some of the major strengths of Standard ML from the view of a user of the language. Not surprisingly, many of these points parallel those mentioned in Appel's critique ([3]). A high-level programming model. A high-level model makes programming more efficient and more reliable by automating and suppressing many low level details such as memory management and data formating. Standard ML's program- ming model is based on the functional programming paradigm, which derives from the lambda calculus. Safety. ML's type system, memory management system, and exception facili- ties combine to guarantee that even buggy ML programs do not \crash" (i.e., fail catastrophically due to some corruption of the computational state or inappropriate manipulation of data). It is possible for a program to fail because an ML exception is raised and never handled. In the interactive system this returns one to top-level, but in a stand-alone program it terminates the program abnormally. It is, of course, also possible for an ML program to produce the wrong result because of a bug, or to fail to terminate. Security and robustness. Static type checking detects many errors at compile time. Error detection is enhanced by the use of pattern matching, which helps ensure coverage of all cases because the compiler can statically detect and report incomplete matches, and by the exception mechanism, which provides a type-secure, disciplined way to deal with potential runtime exceptions. The result is that unexpected runtime errors can be largely avoided or dealt with appropriately. Expressiveness and conciseness. The ability to treat functions as first-class values, the use of higher-order functions to express a wide range of control structures, the use of pattern matching for concise analysis of data, and the availability of imperative constructs provide great expressive power within a simple and uniform conceptual framework. The combination of state and higher-order functions is very powerful, but can cause difficulties in specifying and reasoning about programs (as in object-oriented programming). Flexible strong typing. The ML type system is simple, uniform,1 flexible, and sound. The flexibility is achieved through the use of parametric polymorphism. New types can be defined to match precisely the requirements of a problem, and data ab- straction (i.e., hiding of data representations) is well supported. Automatic inference of most general type schemes streamlines interactive programming. Type checking provides security by detecting statically a large fraction of common mistakes. But perhaps the most valuable aspect of the type system is that it provides a language for designing and expressing data representations and program interfaces and then automatically enforces their proper use through type checking. 1 Any type constructor can be applied to any types without restriction { all types are treated equally. Also, user-defined types are treated the same as primitive types. Modularity. The ML module system is an organic extension of the underlying polymorphic type system ([31, 36]). It provides for separation of interface specifica- tion and implementation and supports abstraction and parameterization. These fa- cilities are very effective in structuring large programs and defining generic, reusable software components. Efficiency. Highly optimizing compilers ([4]) have been developed for ML that, for many applications, produce code whose speed is competitive with those for cor- responding programs written in much lower-level languages such as C. However, space efficiency tends to be significantly worse than for low level languages like C. The cost of automatic memory management and a uniform, simple type system is more intensive use of memory, though advancing compiler technology is reducing this overhead. Multiple modes of usage. In its original incarnation as the metalanguage of the LCF system ([19]), ML played two roles. It was used to program proof tactics and tacticals to automate theorem proving, and it was used as the command language of the interactive LCF system. In several more recent systems such as HOL ([42]), ML also serves as the underlying implementation language for the whole system (LCF itself was implemented in Lisp). These roles can be separated; in particular, it is possible to use an ML compiler in a traditional batch style to generate binary object files that are later linked to create a stand-alone application. Such stand-alone applications must incorporate the runtime system, but they are independent of the compiler and the interactive system. ML has attributes that support all these modes of usage: type inference simplifies use as an interactive command language, many characteristics mentioned above suit it to the role of a symbolic metalanguage, and the module and type systems support large-scale systems implementation. 3 Comments on Language Design Methodology A principled and scientific language design should be guided by parallel efforts and insights coming from three perspectives: semantics, implementation, and last but not least, pragmatics, or how the language is to be used in practice. Ideally, the design of a language should consist of several iterations, each involving development of semantics, experimental implementation, and application experiments. Each iter- ation should use feedback from all three perspectives to adjust design decisions from the previous iteration. Writing a formal semantic definition clearly provides a strong discipline and encourages simplicity and clarity in the language design. Ideally the development of a formal definition should be backed up by investigation of the metatheory of the language (e.g., type soundness theorems, principal typing theorems), and of how to formally specify and reason about programs in the language (i.e., the logic of the language). Unfortunately, the state of program logics is currently rather weak, so designing a language to have a tractable logic seems to be an impractically severe constraint (advocates of pure functional and logic languages may disagree with this point, but such languages have had limited practical impact so far). Developing a prototype implementation of the language forces one to consider the cost of language features and their interactions in terms of implementation complex- ity, and this also favors simplification. The implementation perspective also makes designers consider the consequences of their decisions on execution speed. A new lan- guage design may require new compilation technology, which is risky, but progress would be hindered if new languages were overly constrained by known compilation techniques. How the language is to be used is obviously a central consideration in its design, but when novel features are included it is not easy to fully understand their utility. One excellent way of gaining experience with the use of a new language as it is being designed is to implement the language in itself. This works for general purpose languages, but may be impractical for special purpose languages that are not suitable for language implementations (e.g., implementing Awk in Awk [1]).
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages16 Page
-
File Size-