This paper examines the viability of a language that allows the programmer to mix techniques from the procedural, object-oriented, functional and logic paradigms. It examines such a language from both a commercial and an academic viewpoint. It concludes that there is value in such a language but calls for research into its applicability for large-scale projects.
Dave Wathen, 2005
Stroustrup [BS1] describes multiparadigm programming as "a fancy way of saying programming using more than one programming style, each to its best effect." There are three major paradigms, or programming styles, considered here: object-oriented, functional and logic. To put them in context imperative programming is also discussed.
Imperative, or procedural, programming is the earliest established of the paradigms being considered. As such it is often viewed as the traditional programming style. Its basis is that programs are structured as procedures that manipulate shared data. The data are modelled as locations that hold values. A computation proceeds as a sequence of steps each of which may access and or change the values associated with the locations.
This paradigm is closely related to the Von Neumann architecture [WIKI1] on which practically all general-purpose computers are based. Early programming in machine code was at the level of this architecture. Later assembly language [WIKI2] provided a similar mapping but in a more human-friendly format. Later still third-generation languages added greater abstraction but kept the procedure/data separation.
Two third-generations languages that enjoyed huge success as commercial programming languages are COBOL and C. COBOL [WIKI3] clearly demonstrates this separation; each program consists largely of a DATA and a PROCEDURE division. C [WIKI][KR] is a small language that allows much more structure to the data and procedures through scoping rules but also defines globally accessible data.
As stated this paradigm closely matches the execution model of computers. To program in this paradigm the programmer has to describe the solution in terms of this execution model. Eckel [BE] explains how this causes programming in these languages to be difficult and results in code that is expensive to maintain.
Budd [TB] explains that Alan Kay conceived object-oriented (OO) programming whilst at Xerox PARC. The paradigm creates programs as collections of objects. Each object is an instance of a class that defines the behaviour of all objects of that class. The data operated on by the code defined for the class is associated with each instance. The data is composed of other objects. The language provides certain base classes, such as strings and integers.
Classes have two parts [GB] an interface and an implementation. The interface defines the public face of the class whilst the implementation gives its specific realisation. Since information about the realisation is hidden from the outside, changes to it are local to the class. This is known as encapsulation.
Classes can be organised into an inheritance tree. Classes that inherit from others are known as subclasses and the classes from which they inherit are their superclasses. Whilst some practitioners consider this to be a fundamental part of the paradigm (e.g. [GB]), Kay considers it optional. Inheritance is classified as single or multiple according to the number of superclasses a class may have. Another, orthogonal, classification of inheritance is into implementation or interface.
Interface inheritance allows for multiple realisations of an interface. This allows other code to program to a defined interface and then independently choose the realisation that suits. The realisation can be changed without impacting code that only references the interface. This is known as polymorphic behaviour. To use this technique in isolation from implementation inheritance languages support abstract classes that only define an interface.
Implementation inheritance provides a mechanism for code reuse; classes are able to inherit behaviour from other classes. Subclassing, while convenient, can lead to fragility since subclasses are closely coupled to their superclasses. Often the language provides means by which a subclass can bypass some of the encapsulation of a superclass. An alternative reuse mechanism is composition in which a class uses an instance of another to do work rather than inheriting the behaviour directly [JB][GHJV].
The advantage offered by the OO paradigm is that it allows problems to be decomposed into a (possibly large) number of smaller independent problems.
Pure OO languages such as Smallltalk [WIKI5] and Eiffel [WIKI6] have had limited commercial success. C++ [WIKI7][BS2], which can be crudely thought of as object-oriented extensions to C, Java [WIKI8][AGH] and C# [WIKI9] on the other hand are all very successful. These languages are not pure OO as they have a split type system. In a sense these languages provide the benefits of OO but the class implementations are a mixture of OO and imperative programming.
Abelson, Sussman and Sussman [ASS] describe the functional paradigm as â??programming without assignmentsâ??. Programs are structured as a number of mathematical functions. Each function is implemented in terms of other functions depending ultimately on base functions provided by the language.
Functions themselves are treated as values by the language meaning that they can be used as parameters and return values. This is known as higher-order programming.
Unlike functions in some other programming languages, functions in functional programming languages never exhibit side effects. The lack of assignments means that state is not modelled as changes to storage locations but by the creation of new values. The fact that such functions correspond to functions in mathematics means that they can be reasoned about in the same manner. This opens the possibility for proofs of program correctness.
The lack of side effects allows some optimisations; the order of evaluation is unimportant and so can be deferred. This is known as lazy evaluation. Furthermore the lack of shared changing data locations means that functional programs are always thread safe. Functional programs are therefore good candidates for parallel execution.
As per object-oriented languages, functional languages vary in their purity. Languages such as Haskell [WIKI10] and Miranda [WIKI11] follow the paradigm strictly whilst others such as Scheme [WIKI12] and ML [WIKI13] allow assignments.
Hughes [JH] points out the advantages of functional programming in program modularisation. He argues that higher-order functions and lazy evaluation are the features of functional programming that provide the greatest benefits.
Functional programming has achieved little commercial success to date [AM]. This is due in part to a lack of well-tuned libraries for functional languages and to the run-time behaviour of functional languages. Moran [AM] reports performance as still being an issue 10 years after Pountain [DP] proclaimed in Byte that the issue had been solved.
Another major stumbling block to commercial success for functional programming is the lack of a large body of developers able to program in this paradigm. Software development managers need to know that they can buy in resources with the competencies they are using should their existing resources become unavailable or prove insufficient. Similarly there is risk associated with going against the grain by choosing (commercially) unproven technologies. This contrasts with the alternative: choosing a well-established commercial technology that is known to be adequate. Functional programming needs to offer more than a better mousetrap to succeed in commerce.
Budd [TB] describes the logic-programming paradigm as having derived from work on automatic theorem proving. This paradigm has three important concepts: facts, inference rules and a search mechanism. Facts, or axioms, provide knowledge that is taken to be self-evidently true within the context being addressed. The inference rules define how further facts can be derived from the axioms given. The search mechanism provides a means for trying various sequences of rule applications to determine whether or not some query is true or false. The query to be answered is posed in terms of a possible fact; if the search mechanism can find an application of the rules that derives the possible fact then the query is true.
In logic programming the programmer supplies the facts and inference rules for the problem being addressed. The language supplies the search mechanism.
The most widely used logic programming language is Prolog [WIKI14] but it and, other logic programming languages, have had little commercial success. Mercury [MERC] is a project that recognises this fact and is attempting to create a logic programming language that can.
Combining these paradigms in a single language must derive some benefits or such languages will be rejected. What is hoped for is that the functional approach can be used to allow greater modularity through higher-level programming. It would also be welcomed if quality could be improved through some greater ability to reason about code.
The object-oriented paradigm would provide support for modelling abstract data types. Many successful systems have been built in this paradigm and a wealth of experience in its use exists; it is fair to describe it as the primary paradigm in commercial use.
The inclusion of logic programming should allow a class of problems, those involving inference and searching, to be solved that are not easily addressed by the other paradigms. Further benefit may be derived by the high-level specification of problems that the paradigm permits.
Of course these benefits can already be achieved though the use of multiple languages. The added benefit to be achieved in using one language is to achieve finer-grained integration. Also using a single consistent syntax lowers burden of knowledge on the programmer
Budd [TB] designed Leda as a research tool and teaching device for multiparadigm programming. Its aim is not just to allow a programmer to develop in the paradigm of their choice but to explore synergistic uses of multiple paradigms.
Leda is a small language but Budd has included features to support each of the paradigms:
Leda is a strongly, statically, typed language meaning that the compiler determines the data type of all expressions and ensures that type errors cannot occur. It is useful for object-oriented languages that are strongly typed to include generics. Budd has included this for classes within Leda and extended it to cover functions too.
This is really quite impressive! Leda packs in sufficient features to support all four of the paradigms we are considering yet its grammar only runs to 38 BNF productions, 22 reserved words and 17 operators. This compares to Javaâ??s grammar of 82 BNF productions, 48 reserved words and 37 operators [GJSB].
Fairly obviously, Leda cannot be described as a pure functional programming language. This means that those wishing to use it for pure functional programming need to exercise discipline to avoid using assignment. It also means that programs cannot be optimised in the ways that pure functional programs can be. As a result of this lazy evaluation is achieved explicitly through the use of a by-name calling convention which means it is one further item that needs to be under the control of the programmer.
Leda's object-oriented features provide class definition intuitively. However there are many features that object-oriented programmers are used to that are missing from Leda:
Leda's use of relations covers a lot of ground in the logic-programming paradigm and other features step in to assist with some awkward problems such as negation. Budd also demonstrates the use of this paradigm to cover the closely related field of constraint programming. Syntactically the relation feels overworked in this paradigm and the writing of logic programs does not appear natural. Some syntactic sugar would probably help programs differentiate separate concepts and aid readability quite considerably.
Budd describes a number of cases in which the paradigms can be mixed to achieve various effects. He discusses iteration using object-oriented, functional and logic features. Whilst there is elegance to the solutions based on functional and logical features the simpler object-oriented solution turns out to be the most flexible.
The logic paradigm mixes well with others where searching is required. Relations
perform different roles according to the language construct that they appear in. In
for statements they enumerate all possible variable bindings. In
if statements they perform an existential role; they determine whether or
not a variable binding can be made.
In summary Leda's small size and well thought out design make it an excellent teaching language. It certainly covers the paradigms considered though with more pragmatism than purity. Some interesting mixing of paradigms is explored but none of these seem to provide compelling case for the technique.
Oz [OZ][RH] is a research language developed by the Mozart Consortium. It consists of a kernel language and extended syntaxes that translate to it. The language is strong on concurrency; it supports very lightweight threads and automatic, dataflow, synchronization.
The kernel language includes single-assignment variables, an equality operator that performs unification, cells (state-holding locations), cell assignment and interrogation, procedure definition and calling, threading and exception handling. Altogether there are 18 constructs that are used to underpin the implementations of the broader language features.
The other programming paradigms are given as extensions to the kernel language. These extensions are all translatable to the kernel language. They provide syntax that is easier to use, which generally means briefer, than the kernel language.
The functional paradigm is supplied with syntax for function definition and invocation. Functions translate into procedures in the kernel language. Procedures are treated as values that can be bound to single-assignment variables. This means that they can act as parameters and return values for function thus enabling higher-order functions. Lazy evaluation can be achieved explicitly through functions or implicitly through dataflow synchronization.
Syntax for the object-oriented paradigm consists of class definition with multiple inheritance. Messages (method invocations) are treated as first-class values, which allows for some interesting techniques for compositional OO designs. There is some syntactic support for access control but greater control is achievable using only the kernel language constructs.
Logic programming is based on relational computation similarly to Leda. Alternatives
are specified explicitly using a choice syntax. The language defines search
semantics for alternatives. This is accessed through a lazy Solve function
that is provided. Backtracking is invoked explicitly, using a fail
statement, or implicitly, when unification fails.
Constraint programming is also supported through more syntactic and semantic features. Operators are defined to allow for the specification of constraints. The operational model is extended to include computation spaces that allow multiple potential solutions to be explored.
Oz is a very dynamic language. It is dynamically typed and fundamental structures such as functions and classes are defined dynamically. This permits much flexibility; for example it allows for a form of generics, for aspect-oriented programming and for reflection. Statically typed languages provide error detection at compile time. Oz's dynamic model prohibits this; type errors are not detected until run time.
As is to be expected for a research language only a small set of libraries are available for the language.
As noted, and expected, the kernel language is small. The extensions to provide suitable syntax for each paradigm still keep the language small. These extended syntaxes each suit their paradigm and would be reasonably familiar to practitioners. As in Leda the most strained syntax appears to be that used for logic programming.
As a teaching language Ozâ??s approach could add great value. Studying the relationships between the kernel language and the extended syntaxes draws out the fundamental features of the paradigm from devices added to aid the programmer. The differences between the subsets of the kernel language required to support each paradigm draw out the underlying differences between the paradigms.
Python [PYTH] is primarily an object-oriented language. The python website describes it as: â??an interpreted, interactive, object-oriented programming languageâ??.
However Python includes support for functional programming. Functions can be defined and are treated as first-class values (objects) [DM]. Logic programming is not supported directly but can be incorporated as a library [PYLOG][LL].
Python has achieved some success as a commercial language . Reasonably large libraries have been built up for it.
Python is developed as an open source project, which makes it popular among advocates of the open-source approach. As such it is often bundled with Linux distributions. This ensures that it is becoming available to a wide audience and makes the language's prospects interesting. It has probably established enough of a foothold to ensure that it will be in continued use for some time yet. Perl [PERL], another open source language, is in widespread commercial and non-commercial use. This demonstrates that open source languages can be successful.
One alternative to direct support for multiple paradigms within a single language is to emulate those features using an essentially single-paradigm language.
Abelson, Sussman and Sussman [ASS] produce in Scheme an emulation of logic programming that allows the expression of facts and rules in a succinct form that looks comparable to Prolog. They also touch on the world of objects but eschew the object-oriented paradigmâ??s concepts of classes and inheritance.
Belapurkar [AB] shows the emulation of functional programming in Java. The emulation successfully reproduces some of the features of the functional paradigm but the code produced is clumsy and highlights the lack of direct language support.
Whilst these examples show that emulation is possible there needs to be a strong motivation for programmers of the language to use the technique. Where the syntax does not make the approach easy, resistance will be met unless the perceived benefits are great. This is unlikely since, if the benefits were that obvious, suitable features would have been included in the language from the start.
Furthermore programming languages are often not used with complete freedom. Each language also builds up a common practice in its application. A programmerâ??s peers and management frequently enforce this common practice in the form of coding standards or guidelines[SM]. This is done to aid understandability of code produced and hence reduce the maintenance costs, which are significant for most software projects [FB]. Emulation of another programming paradigm would normally be discouraged as operating outside of this practice.
The emulation of functional programming in Java mentioned above was achieved in part through the use of a library [AJCF]. As noted this did not lead to a graceful implementation.
The logical paradigm can sit more easily into object-oriented code though. This is because it can be seen as solving a particular problem and so viewed as a separate component of the system. Interfacing this component into the rest of the system as one or more objects leads to a natural integration. An example is the Java Theorem Prover [JTP].
Using separate languages for each paradigm is another way of proceeding. For this to be useful the artefacts produced by each language need to interoperate. There are a variety of ways of achieving this:
Interoperability through data is simple to achieve. Data flows from one artefact to the next through some operating-system-provided mechanism such as a file system, pipes or sockets.
Compiled code from different languages can interoperate if they are linked together and both comply with a common calling convention. This provides low-level interoperability and is effectively just an efficient fine-grained in-process version of data interoperability.
One such infrastructure that supports multiple languages is OMGâ??s CORBA [CORBA]. This is aimed at distributed applications, those where communication is expected to be across a network. Components are viewed as objects with defined interfaces. Language independence is provided through an interface definition language (IDL) that has bindings to implementation languages. Bindings exist for C, C++, Java, COBOL, Smalltalk, Ada, Lisp, Python, and IDLscript. Unsurprisingly OO languages dominate this list; there are no logic-programming languages, one functional language (Lisp) and one multi-paradigm language (Python).
CORBA enjoyed a period of commercial success but this is dwindling . This is probably due to the difficulties in architectures that attempt to hide network topology. The concept of distributed object models is to treat remote objects similarly to local objects. The latency involved in network communications makes this impractical . These issues similarly affected early use of J2EE, see Using Entity Beans as Fine-Grained Objects in Alur, Crupi and Malks [ACM].
ILU [ILU] is a similar technology that interoperates with CORBA. It allows for efficient in-process inter-language communication. It similarly covers Lisp and Python but no logic-programming languages. The project is at a fairly early stage; it is currently available as a beta release.
Microsoftâ??s .NET is their strategic approach to software development. It includes a platform designed to run artefacts produced in multiple languages together. This is the Common Language Runtime (CLR). It provides â??cross-language integration, code access security, object lifetime management, and debugging and profiling support.â??
The CLR is an implementation of the Common Language Infrastructure (CLI). The CLI defines a multithreaded execution framework and memory model that supports the Common Type System (CTS) to allow for data interchange. Metadata is provided for the CTS to allow for reflection and tool integration. Artefacts running on the CLR conform to the Common Language Specification (CLS) that defines usage conventions for the CTS to allow interaction between artefacts.
The provisions for debugging and profiling show that the platform has been designed for practical use. Being the foundation for Microsoftâ??s strategic approach to software development means that the platform is well supported. For example there are large libraries that integrate into the platform.
The platform is primarily available, as supplied by Microsoft, for use under their operating systems. Mono [MONO] is an open-source effort to produce a CLI implementation for Linux. Microsoft also has a project to support FreeBSD and Mac OS X [ROTOR].
There are many languages supported by the .NET platform including examples from all of the paradigms that are considered here [DNP].
Whilst not originally designed to support multiple languages the Java Virtual Machine (JVM) platform also incorporates many of these features. A large number of languages have been adapted to this platform [RT]. Again this includes examples from all of the paradigms considered here. There is also cross-language debugging support [JSR45].
The primary advantage of integration between separate languages is that the languages for the separate paradigms are well established. There is a body of literature to support them. There are large amounts of code already produced and in use.
The main disadvantages are maintenance and the level of integration achievable. Maintaining a system produced in multiple languages requires a greater range of skills than single-language projects do. The level of integration achievable through this approach cannot achieve the sort of fine-grained usage demonstrated by multiparadigm languages.
For a new language to establish itself for use in commercial development requires it to deliver enough benefit for its selection over the existing languages of choice. Given that commercial projects usually involve the development of software under cost and time constraints [FB], one appealing benefit is improved productivity.
Improved productivity can result from a language that presents a model that is easier to understand. COBOL introduced a coding style that was verbose but intended to make programs far more readable that previous languages had done. C introduced a compact language with strong support for structured programming [WIKI15], a technique that had been shown to produce less fragile code. Whilst the approach could be used in existing languages, its use could not be enforced.
A related factor is the cost of adoption; lowering this provides a greater chance that the benefits offered will appeal enough for a languageâ??s adoption. This is commonly achieved by basing the language on an existing dominant language. C++ provides object orientation using syntax familiar to C programmers. Whilst C++ is not a strict superset of C, it is to the extent that C programmer can effectively program in C using C++. At its introduction, this allowed the new paradigm to be adopted gradually. Similarly Javaâ??s syntax comes from the C++/C line. This allowed it to be quickly learnt by C++ programmers. Its appeal to those programmers was that it was a much smaller language that offered considerably easier memory management.
A further factor affecting language adoption is its use in academia. This was another factor in Câ??s success. C is the foundational language of the Unix operating system. Due to US regulation of AT&T the source for Unix was given to the academic community [AT]. This led to it being much studied and developed by that community. When students who had passed through the university system reached industry they brought with them an understanding and familiarity with Unix and C.
As noted cost and time pressures heavily influence commercial development. Duplicated effort is wasted so ways to reduce it appeal. Generative programming [CE] is an approach that could alleviate much of this duplication. One of the techniques, Aspect Oriented Programming, is already starting to gain some support [JBOSS] [AJ].
Despite some of the concerns expressed above over the use of multiple languages for project development, it is common practice. Generative programming suggests the use of more languages, even the creation of specific languages, for software development. The conclusion would seem to be that using multiple languages is good if it reduces the overall complexity of the project. In light of this, coordinated tools support for multiple languages would assist manageability [LDT].
Both academic and commercial multiparadigm languages exist and are in use.
Both Leda and Oz present useful languages that can be used in academia. Of the two Oz seems the most useful. Its approach draws out the fundamental features of each paradigm and is extensible to model and explore more paradigms than have been considered here.
Multiparadigm languages are not in heavy use commercially. In the case of Python it is not clear that its support for multiparadigm programming is a driver for its adoption or a major factor in its use.
If commercial programmers are to adopt multiparadigm practices there needs to be a route though which this can happen. Universities can influence this by ensuring that students leave their establishments with an understanding of the different paradigms and of the possibilities for multiparadigm programming. A research programme is needed to investigate and quantify the benefits of using a multiparadigm language for large software development projects. Lastly a foothold is needed in the realm of commercial development.
The kernel language approach of Oz has application beyond academia. The desire for co-ordinated tool support for development using multiple languages could be founded on the technique. In Oz the kernel language supports extended syntaxes to create a multiparadigm language but there is no reason that other syntaxes cannot be similarly translated into kernel language. The result would be a language for modelling programming languages and tool support.
The kernel language would provide an intermediate representation derived from multiple source languages that could then be translated to one or more runtime models (such as direct, CLR or JVM executables). The common runtime so achieved provides support for legacy code and access to libraries.
The two levels of translation, source-to-kernel and kernel-to-runtime, would be tracked to provide source-level error reporting, debugging and profiling. Common tools would operate on source languages using data contained in annotations included in the definition used drive the source-to-kernel translation.
If multiparadigm programming with the kernel language approach so formed the basis of useful tooling for commercial programmers, it would provide the foothold required. If successful, it would provide evidence for the practicality of the approach.
| [.NET] | http://www.microsoft.com/Net/Basics.aspx |
| [AB] | Abhijit Belapurkar, http://www-106.ibm.com/developerworks/library/j-fp.html?ca=drs-j2904 |
| [ACM] | John Crupi, Dan Malks and Deepak Alur (2003) Core J2EE Patterns: Best Practices and Design Strategies, Prentice Hall PTR |
| [AGH] | Ken Arnold, James Gosling, David Holmes (2000) The Java Programming Language (Third Edition), Addison-Wesley |
| [AJ] | AspectJ, http://eclipse.org/aspectj/ |
| [AJCF] | Apache Jakarta Commons Functor, http://jakarta.apache.org/commons/sandbox/functor/ |
| [AM] | Andrew Moran, http://www.galois.com/cufp/CUFP-Report.pdf |
| [ASS] | Harold Abelson, Gerald Jay Sussman and Julie Sussman (1996) Structure and Interpretation of Computer Programs, MIT Press |
| [AT] | Andrew S. Tanenbaum (2001) Modern Operating Systems, Prentice Hall PTR |
| [BE] | Bruce Eckel (2003) Thinking in Java (Third Edition), Prentice Hall PTR |
| [BS1] | http://www.research.att.com/~bs/bs_faq.html#multiparadigm |
| [BS2] | Bjarne Stroustrup (2000) The C++ Programming Language (Special Edition), Addison-Wesley |
| [CE] | Krzysztof Czarnecki and Ulrich Eisenecker (2000) Generative Programming: Methods, Techniques and Applications, Addison-Wesley |
| [CORBA] | http://www.omg.org/technology/documents/formal/corba_iiop.htm |
| [CW] | Computerworld Development Survey, http://www.computerworld.com/developmenttopics/development/story/0,10801,100542,00.html |
| [DM] | David Mertz, http://www-106.ibm.com/developerworks/linux/library/l-prog.html |
| [DNP] | http://www.dotnetpowered.com/languages.aspx |
| [DP] | Dick Pountain, http://www.byte.com/art/9408/sec11/art1.htm |
| [FB] | Frederick P. Brooks (1995) The Mythical Man Month and Other Essays on Software Engineering (Anniversary Edition), Addison-Wesley |
| [GB] | Grady Booch (1994) Object-Oriented Analysis and Design with Applications (Second Edition), Addison-Wesley |
| [GHJV] | Erich Gamma, Richard Helm, Ralph Johnson and John Vissides (1995) Design patterns : elements of reusable object-oriented software, Addison-Wesley |
| [GJSB] | James Gosling, Bill Joy, Guy Steele and Gulad Bracha (2000) The Java Language Specification, (Second Edition), Addison-Wesley |
| [ILU] | ftp://ftp.parc.xerox.com/pub/ilu/ilu.html |
| [JB] | Joshua Bloch (2001) Effective Java, Addison-Wesley |
| [JBOSS] | http://www.jboss.org/products/aop |
| [JH] | John Hughes, Why Functional Programming Matters, http://www.math.chalmers.se/~rjmh/Papers/whyfp.html |
| [JSR45] | http://www.jcp.org/en/jsr/detail?id=45 |
| [JTP] | Java Theorem Prover, http://www.ksl.stanford.edu/software/JTP/ |
| [KR] | Brian W Kernighan and Dennis M. Ritchie (1988) The C Programming Language (Second Edition), Prentice Hall |
| [LDT] | Eclipse Language Development Toolkit, http://www.eclipse.org/proposals/eclipse-ldt/index.html |
| [LL] | http://www.logilab.org/projects/constraint |
| [MERC] | http://www.cs.mu.oz.au/research/mercury/ |
| [MONO] | http://www.mono-project.com/Main_Page |
| [OZ] | http://www.mozart-oz.org/ |
| [PYLOG] | http://christophe.delord.free.fr/en/pylog/ |
| [PYTH] | http://www.python.org/ |
| [RH] | Peter Van Roy and Seif Haridi (2004) Concepts, Techniques, and Models of Computer Programming, MIT Press |
| [ROTOR] | http://msdn.microsoft.com/net/sscli |
| [RT] | http://www.robert-tolksdorf.de/vmlanguages.html |
| [SM] | Steve C. McConnell (1993) Code Complete, Microsoft Press |
| [TB] | Timothy A. Budd (1995) Multiparadigm Programming In Leda, Addison-Wesley |
| [WIKI1] | http://en.wikipedia.org/wiki/Von_Neumann_architecture |
| [WIKI2] | http://en.wikipedia.org/wiki/Assembly_language |
| [WIKI3] | http://en.wikipedia.org/wiki/COBOL |
| [WIKI4] | http://en.wikipedia.org/wiki/C_programming_language |
| [WIKI5] | http://en.wikipedia.org/wiki/Smalltalk |
| [WIKI6] | http://en.wikipedia.org/wiki/Eiffel_programming_language |
| [WIKI7] | http://en.wikipedia.org/wiki/C_Plus_Plus |
| [WIKI8] | http://en.wikipedia.org/wiki/Java_programming_language |
| [WIKI9] | http://en.wikipedia.org/wiki/C_Sharp |
| [WIKI10] | http://en.wikipedia.org/wiki/Haskell_programming_language |
| [WIKI11] | http://en.wikipedia.org/wiki/Miranda_programming_language |
| [WIKI12] | http://en.wikipedia.org/wiki/Scheme_programming_language |
| [WIKI13] | http://en.wikipedia.org/wiki/ML_programming_language |
| [WIKI14 | ]http://en.wikipedia.org/wiki/Prolog |
| [WIKI15] | http://en.wikipedia.org/wiki/Structured_programming |