This is an old revision of this page, as edited by 64.136.201.127 (talk) at 13:48, 3 April 2004. The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.
Revision as of 13:48, 3 April 2004 by 64.136.201.127 (talk)(diff) ← Previous revision | Latest revision (diff) | Newer revision → (diff)Note: This article is intended to someday replace programming language. It is in my namespace for the moment only because it's not yet complete enough to "go live". You may edit this article, if you wish, just as freely as any other. In fact, contributions from other users will most likely be improvements, and may also hasten the day that we can make this page live. See the talk page for the main article for discussion related to the article and this rewrite. k.lee
A programming language is a systematic method by which people describe computations to other people, and sometimes to mechanical computers as well. Programming languages exist because other forms of human expression---such as natural languages---are not well-suited to describing computation. Computations expressed in programming languages are called programs, and the act of constructing programs is called programming.
Why programming languages?
Like other specialized languages, such as musical notation and mathematical formulae, programming languages facilitate the communication of a specific kind of knowledge---namely, computation, or the task of organizing and manipulating information. For example, a programming language might enable its user to express the following:
- A step-by-step procedure for sorting a list of names in alphabetical order.
- A set of precise rules for predicting the future motion of planets in the solar system.
- A specific protocol allowing computers to communicate over the Internet.
Programming languages differ from most other forms of human expression in that they force the author to write programs with exceeding precision and completeness. In a natural language, or even mathematical notation, authors have considerable freedom to be vague and incomplete. For example, consider natural language:
- Speakers can leave things out, because humans excel at "filling in the gaps" of a partial statement. If someone says: "Going to the store," the listener might use the context to fill in the missing words: "I am going to the store on the corner."
- Speakers can make grammatical errors, because humans excel at compensating for minor human errors. If someone says, "I am going to the store am the corner," the listener can usually tell that "am" is meant to be "on".
By contrast, in a programming language, every part of every computation must be expressed explicitly and exactly. Each phrase in a program corresponds unambiguously to its literal meaning, and no more. If the author of a program states that the program should perform an incorrect step, the program's meaning will include that incorrect step. If the author omits a necessary step, the program's meaning will not include that step. Therefore, in order to write a "correct" program, the author must be correct in every detail.
In return for this exacting discipline, programming languages reward the user with a unique power: many programming languages are executable by a mechanical computer. In other words, tasks expressed in some programming languages can be performed autonomously by a computer, without human intervention. Therefore, programming languages have enormous practical utility---they enable the construction of artifacts (programs) that automatically perform tasks. The entire information technology industry is built around the construction and use of programs. A programming language implementation is a system that enables a computer to execute a program written in a programming language. Programming language implementations typically come in two flavors: interpreters and compilers.
However, not all programming languages have executable implementations. In particular, most foundational languages---also called core languages or calculi (singular calculus)---are purely mathematical constructs. The most prominent foundational language is Alonzo Church's lambda calculus. Computer scientists use such languages to study the fundamental properties of programming languages; often, language designers apply the lessons learned from formal calculi in the design of practical programming languages. For example, the lambda calculus is the basis of Lisp. See also type theory.
Since the dawn of programming languages, countless languages have been designed from scratch, altered to meet new needs, combined with other languages, and fallen into disuse. Although there have been attempts to make one "universal" computer language that serves all purposes, all of them have failed. The need for diverse computer languages arises from the diversity of contexts in which languages are used:
- Programs range from tiny scripts written by individual hobbyists to huge systems written by hundreds of programmers.
- Programmers range in expertise from novices (who need simplicity above all else) to experts (who may be comfortable with considerable complexity in the language).
- Programs may need to extract the right amount of performance on platforms ranging from tiny microcontrollers to supercomputers.
- Finally, programmers may simply differ in their tastes or habits.
Note: Programming languages vs. computer languages
Programming languages are a subset of computer languages. Generally, a "programming language" is designed to express computation, whereas the term "computer language" can denote any language used by a computer or its users. For example, a markup language is a computer language, but generally markup languages are designed to describe primarily data, not computation.
Elements of programming languages
A programming language's surface form---that is, how programs are represented to a reader---is its syntax. Programming languages vary widely in this surface form. Most programming languages are textual---that is, they consist of sequences of "words" and "punctuation marks", much like written natural languages. However, some exotic programming languages are partly or entirely "visual"---such visual programming languages use spatial relationships among stylized pictorial representations to communicate their meaning, much like musical notation and Venn diagrams.
Regardless of their surface form, all programming languages also specify a semantics, or "meaning", for each syntactic construct in the language. In textual programming languages, the syntactic constructs are words and phrases; in visual languages, the "syntax" consists of spatial arrangements of pictures, text, or both. In either case, the essence of a programming language is the meaning that it assigns to the various constructs it provides.
Syntax
The syntax of a language describes what sequences or arrangements of symbols is legal in the language. The syntax does not describe meaning; that is the job of semantics. Most commonly used languages are textual, so here we describe only the syntax of textual languages.
Programming language syntax is usually defined using a combination of regular expressions (for lexical structure) and Backus-Naur Form (for context-free structure). The use of these devices gives programming language syntax a precise definition founded in formal language theory. For example, a simplified grammar for Pure Lisp is given by the following:
expression ::= atom | list atom ::= number | symbol number ::= + symbol ::= .* list ::= '(' expression* ')'
This indicates that:
- an expression is an atom or a list;
- an atom is a number or a symbol;
- a number is one or more digits;
- a symbol is a letter followed by zero or more of any characters; and
- a list is a pair of parentheses, with any number of expressions inside it.
The following are all expressions in this grammar:
12345 () (a b c232 (1))
Not all syntactically correct programs are semantically correct---in other words, it is possible for a program to have the proper syntax, but mean nothing, or mean something incorrect. This is analogous to the fact that, in natural languages, a sentence may appear grammatically correct but have no meaning, or a false meaning. For example:
- The following English sentence is grammatically well-formed but means nothing: "The grundlefarb timbles over the slothrop."
- This English sentence is syntactically well-formed, and has a meaning, but its meaning is incorrect: "The grass on a baseball field is usually purple."
Therefore, it naturally arises that a programming language must have a semantics, or "a set of rules about meaning", as well as its syntax.
Semantics
Although programmers often notice the syntax of a programming language first, the essence of a programming language is its semantics. In fact, it is possible to have a single language with multiple syntaxes---the ambient calculus of Cardelli and Gordon, for example, has both a pictorial and a textual syntax, both exactly quivalent in meaning.
Data and types
LEFT OFF HERE
Internally, all data in a modern digital computer are stored simply as on-off (binary) states. The data typically represent information in the real world such as names, bank accounts and measurements and so the low-level binary data are organised by programming languages into these high-level concepts.
The particular system by which data are organized in a program is the type system of the programming language; the design and study of type systems is known as type theory. Languages can be classified as statically typed systems (e.g. C++ or Java), and dynamically typed languages (e.g. Lisp, JavaScript, Tcl or Prolog). Statically-typed languages can be further subdivided into languages with manifest types, where each variable and function declaration has its type explicitly declared, and type-inferred languages (e.g. MUMPS, ML).
With statically-typed languages, there usually are pre-defined types for individual pieces of data (such as numbers within a certain range, strings of letters, etc.), and programmatically named values (variables) can have only one fixed type, and allow only certain operations: numbers cannot change into names and vice versa. Dynamically-typed languages treat all data locations interchangeably, so inappropriate operations (like adding names, or sorting numbers alphabetically) will not cause errors until run-time. Type-inferred languages superficially treat all data as not having a type, but actually do sophisticated analysis of the way the program uses the data to determine which elementary operations are performed on the data, and therefore deduce what type the variables have at compile-time. Type-inferred languages can be more flexible to use, while creating more efficient programs; however, this capability is difficult to include in a programming language implementation, so it is relatively rare.
It is possible to perform type inference on programs written in a dynamically-typed language, but it is legal to write programs in these languages that make type inference infeasible.
Sometimes statically-typed languages are called "type-safe" or "strongly typed", and dynamically-typed languages are called "untyped" or "weakly typed"; confusingly, these same terms are also used to refer to the distinction between languages like Eiffel, Oberon, Lisp, Scheme, or OCaml, in which it is impossible to use a value as a value of another type and possibly corrupt data from an unrelated part of the program or cause the program to crash, and languages like FORTH, C, assembly language, C++, and most implementations of Pascal, in which it is possible to do this.
Sometimes type-inferred and dynamically-typed languages are called "latently typed."
Most languages also provide ways to assemble complex data structures from built-in types and to associate names with these new combined types (using arrays, lists, stacks, files). Object oriented languages allow the programmer to define new data-types, "Objects", along with the "Functions" to operate upon these new data-types, "Methods", by assembling complex structures along with behaviors specific to those newly defined data structures.
Aside from when and how the correspondence between expressions and types is determined, there's also the crucial question of what types the language defines at all, and what types it allows as the values of expressions (expressed values) and as named values (denoted values).
Low-level languages like C typically allow programs to name memory locations, regions of memory, and compile-time constants, while allowing expressions to return values that fit into machine registers; ANSI C extended this by allowing expressions to return struct values as well. Functional languages often allow variables to name run-time computed values directly instead of naming memory locations where values may be stored. Languages that use garbage collection are free to allow arbitrarily complex data structures as both expressed and denoted values. Finally, in some languages, procedures are allowed only as denoted values (they cannot be returned by expressions or bound to new names); in others, they can be passed as parameters to routines, but cannot otherwise be bound to new names; in others, they are as freely usable as any expressed value, but new ones cannot be created at run-time; and in still others, they are first-class values that can be created at run-time.
Control
Once data has been specified, the machine must be instructed how to perform operations on the data. Elementary statements may be specified using keywords or may be indicated using some well-defined grammatical structure. Each language takes units of these well-behaved statements and combines them using some ordering system. Depending on the language, differing methods of grouping these elementary statements exist. This allows one to write programs that are able to cover a variety of input, instead of being limited to a small number of cases. Furthermore, beyond the data manipulation instructions, other typical instructions in a language are those used for control flow(branches, definitions by cases, conditionals, loops, backtracking, functional composition).
Naming, abstraction, and parameterization
The core of the idea of reference is that there must be a method of indirectly designating storage space. The most common method is through named variables. Depending on the language, further indirection may include references that are pointers to other storage space stored in such variables or groups of variables. Similar to this method of naming storage is the method of naming groups of instructions. Most programming language use macro calls, procedure calls or function calls as the statements that use these names. Using symbolic names in this way allows a program to achieve significant flexibility, as well as a high measure of reusability. Indirect references to available programs or predefined data divisions allow many application-oriented languages to integrate typical operations as if the programming language included them as higher level instructions.
Specifying language semantics
There are six ways in which programming language semantics are described; all languages use at least one, and some languages combine more than one:
- Axiomatic semantics.
- Denotational semantics.
- Operational semantics.
- Natural language descriptions.
- Reference implementations.
- Test suites
The first three of these are grounded in mathematics, and have the advantage of being precise, compact, and unambiguous. Programming languages whose semantics are described using one of these methods can reap many benefits. For example:
- Formal semantics enable mathematical proofs of program correctness;
- Formal semantics facilitate the design of type systems, and proofs about the soundness of those type systems;
- Formal semantics establish unambiguous and uniform standards for implementations of the language, making it more likely that programs written in those languages will be portable across implementations.
By contrast, natural language descriptions tend to be imprecise, verbose, and ambiguous. They do not lend themselves to proofs, either about individual programs or about the programming language's type system. On the other hand, it is relatively easy for inexperienced language designers to write a natural-language description of a programming language's semantics. Additionally, formulating a rigorous mathematical semantics of a large, complex, practical programming language is a daunting task even for experienced specialists, and the resulting specification can be difficult to understand except by a small priesthood of experts.
To these objections, advocates of formal semantics reply that if a language is so complicated that a formal semantics cannot be defined for it, then a natural language description is likely to fare no better. Natural language description can always be defined as a supplement to a formal semantics. Also, formal semantics advocates point out that the imprecision of natural language as a vehicle for programming language semantics has caused problems in the real world: for example, the semantics of Java threads were specified in English, and it was later discovered that the specification did not provide adequate guidance for implementors. Writing truly portable multithreaded Java programs remains challenging to this day.
Regardless of the relative merits of formal and natural-language semantics, in practice most widely-used languages are specified using natural language description. This description usually takes the form of a reference manual for the language. The manuals for widely used languages usually run in the hundreds of pages. For example, the print version of the Java Language Specification, 2nd Ed. is 544 pages long.
By contrast, The Definition of Standard ML, Revised, which uses operational semantics to describe ML, is 114 pages long. The Revised Report on the Scheme (R5RS) uses denotational semantics to describe Scheme, and is 50 pages long. (These comparisons should be taken with the caveat that Scheme and ML are both arguably simpler languages than Java.)
The fourth means of specifying language semantics is with a reference implementation. In this approach, a single implementation of the programming language is designated as authoritative, and its behavior is held to define the proper behavior of a program written in this language. This approach has several attractive properties. First, it is precise, and requires no human interpretation: all disputes as to the meaning of a program can be settled simply and unambiguously by executing the program on this implementation.
On the other hand, this approach also has several drawbacks. Chief among them is that it conflates limitations of the reference implementation with properties of the language. For example, if the reference implementation has a bug, then that bug must be considered to be an authoritative behavior. Another drawback is that programs written in this language are likely to rely on quirks in the reference implementation, hindering portability across different implementations.
Nevertheless, several languages effectively take the reference implementation approach. For example, the Perl interpreter is considered to define the authoritative behavior of Perl programs. In the case of Perl, nobody has ever produced an independent implementation of the language, and the Perl executable itself is highly portable, so some of the drawbacks of using a reference implementation to define the language semantics are moot.
The final way of specifying the meaning of a language is with a test suite. In this approach, the language designer writes a number of example programs in the language, and then describes how those programs ought to behave --- perhaps by writing down their correct outputs. The programs, plus their outputs, are called the "test suite" of the language. Any correct language implementation must then produce exactly the correct outputs on the test suite programs.
This technique's chief advantage that it is easy to determine whether a language implementation is correct. The user can simply execute all the programs in the test suite, and compare the outputs to the desired outputs. If the outputs are the same, the language implementation is correct. If not, the implementation is incorrect. However, when used by itself, the test suite approach has major drawbacks as well. For example, users want to run their own programs, which are not part of the test suite; indeed, a language implementation that could only run the programs in its test suite would be largely useless. But a test suite does not, by itself, describe how the language implementation should behave on any program not in the test suite; determining that behavior requires some extrapolation on the implementor's part, and different implementors may disagree.
Therefore, in common practice, test suites are used only in combination with one of the other language specification techniques, such as a natural language description or a reference implementation.
History of programming languages
Prehistory: Foundations and Assembly
The first foundational programming languages predate the modern computer entirely. The most important of these is the lambda calculus, invented in the 1930s by Alonzo Church of Princeton University. Alternatively, the instructions of the Turing machine, developed in the 1930s by Alan Turing (who studied with Church at Princeton), can be viewed as a "foundational assembly language". However, unlike the lambda calculus, Turing's code does not serve well as a foundation for higher-level languages---its principal use is in rigorous analyses of algorithmic complexity. It is well-suited to this task because every operation in a Turing machine takes constant time, whereas the lambda calculus's reduction---its most fundamental operation---can take linear time proportional the size of the function body.
Like many "firsts" in computer history, the first non-foundational programming language is hard to identify. The designation depends on how much power and human-readability one requires of a form of communication before granting it the status of "programming language". Jacquard looms and Charles Babbage's Difference Engine both had simple, extremely limited languages for describing the actions that these machines should perform. One can even regard the punch holes on a player piano scroll as a limited domain-specific programming language, albeit one not fit for human consumption.
However, these machine languages were not Turing complete---that is, "programs" created in these languages would be fundamentally less powerful than a general-purpose computer, even if they were given infinite memory (see Church-Turing thesis). The first Turing complete programming languages were probably the assembly languages of the earliest electronic computers. In assembly languages, each construct in the language corresponds exactly to one instruction in a physical computer. For example, a machine might have an instruction that added the contents of two machine registers, and placed the result in a third register; such an instruction might be represented in assembly language using the following text:
ADD R1, R2, R3
It was soon discovered that programming in assembly language was extraordinarily tedious and error-prone. Individual machine instructions were too "low-level" to construct large programs---doing so was akin to constructing a building by gluing together individual grains of sand. As demand for more complex programs grew, programmers soon realized that higher-level programming languages were necessary.
The 1950s: The Founding Three, and Algol
In the 1950s, the first three modern programming languages were invented:
- LISP, the "LISt Processor", invented by John McCarthy et al.;
- FORTRAN, the "FORmula TRANslator, invented by John W. Backus et al.; and
- COBOL, the COmmon Business Oriented Language, created by the Short Range Committee, heavily influenced by Grace Hopper.
Descendants of all three are still in use today, although Lisp (which most people no longer write with all capitals) has influenced later languages to a much greater extent than the other two.
The next major milestone in computer languages came between 1958 and 1960, when a committee composed jointly of American and European computer scientists held a series of meetings in Europe to design "a new language for algorithms". These meetings culminated in the Algol 60 Report, which described Algol 60, the "ALGOrithmic Language". This report consolidated many ideas then circulating in the languages community, and also featured two key innovations:
- The use of Backus-Naur Form (BNF) for describing the language's syntax. Nearly all subsequent programming languages have used a variant of BNF to describe the context-free portion of their syntax.
- The introduction of lexical scoping for names in arbitrarily nested scopes.
Algol 60 was never fully implemented or widely used---partly for political reasons, stemming from IBM's introduction of PL/I, and partly due to ambiguities and errors in the language specification. However, it represented a major step forward, and was influential in the design of later languages, including Simula, Pascal, Scheme, and Modula. Additionally, most modern computer science textbooks use an Algol-like notation for pseudocode descriptions of algorithms.
1967-1978: Establishing Fundamental Paradigms
The period from the late 1960s to the late 1970s brought a major flowering of programming languages, comparable to the Cambrian explosion of biology. Most of the major language paradigms now in use were invented in this period:
- Object-oriented programming was invented by Nygaard and Dahl in Simula, which reached maturity in 1967. In 1976, Smalltalk followed Simula with a refinement of object-oriented concepts.
- C, an early systems programming language, was developed by Dennis Ritchie and Ken Thompson at Bell Labs in between 1969 and 1973.
- Prolog, designed in 1972 by Colmerauer, Roussel, and Kowalski, was the first logic programming language.
- ML built a polymorphic type system (invented by Robin Milner in 1978) on top of Lisp, pioneering statically typed functional programming languages.
Each of these languages spawned an entire family of descendants, and most modern languages count at least one of them in their ancestry.
The 1960s and 1970s also saw considerable debate over the merits of "structured programming", which essentially meant programming without the use of GOTO. This debate was closely related to language design: some languages did not include GOTO, which forced structured programming on the programmer. Although the debate raged hotly at the time, nearly all programmers now agree that, even in languages that provide GOTO, it is bad style to use it except in rare circumstances. As a result, later generations of language designers have found the structured programming debate tedious and even bewildering: first, the answer seems obvious in retrospect; and second, there were far greater revolutions afoot in language design at the time.
The 1980s: Consolidation, Modules, Performance
In contrast to the remarkable innovation of the previous decade, the 1980s were years of relative consolidation. C++ combined object-oriented and systems programming. The United States government standardized Ada, a systems programming language intended for use by defense contractors. In Japan and elsewhere, vast sums were spent investigating so-called "fourth generation" languages that incorporated logic programming constructs. The functional languages community moved to standardize ML and Lisp. Rather than inventing new paradigms, all of these movements elaborated upon the ideas invented in the previous decade.
However, one important new trend in language design was an increased focus on programming for large-scale systems through the use of modules, or large-scale organizational units of code. Modula, Ada, and ML all developed notable module systems in the 1980s. Module systems were often wedded to generic programming constructs---generics being, in essence, parameterized modules (see also parametric polymorphism).
Furthermore, although major new paradigms for programming languages did not appear, many researchers expanded on the ideas of prior languages and adapted them to new contexts. For example, the languages of the Argus and Emerald systems adapted object-oriented programming to distributed systems.
The 1980s also brought great advances in programming language implementation. The RISC movement in computer architecture hypothesized that hardware should be designed for compilers rather than for human assembly programmers. Aided by processor speed improvements that enabled increasingly aggressive compilation techniques, the RISC movement sparked greater interest in compilation technology for high-level languages.
Language technology continued along these lines well into the 1990s. However, the adoption of languages has always been driven by the adoption of new computer systems, and in the mid-1990s one of the most important new systems in computer history suddenly exploded in popularity.
The 1990s: The Internet Age
The rapid growth of the Internet in the mid-1990's was the next major historic event in programming languages. By opening up a radically new platform for computer systems, the Internet created an opportunity for new languages to be adopted. In particular, the Java programming language rose to popularity because of its early integration with the Netscape Navigator web browser, and various scripting languages achieved widespread use in developing customized applications for web servers. Neither of these developments represented much fundamental novelty in language design---for example, the design of Java was a more conservative version of ideas explored many years earlier in the Smalltalk community---but the widespread adoption of languages that supported features like garbage collection and strong static typing was a major change in programming practice.
Current trends in programming languages
Programming language evolution continues apace, in both industry and research. Some notable current directions include:
- Mechanisms for adding security and reliability verification to the language: extended static checking, information flow control, static thread safety.
- Alternative mechanisms for modularity: mixins, delegates, aspects.
- Component-oriented software development.
- Increased emphasis on distribution and mobility.
- Integration with databases, including XML and relational databases.
Programming language implementation
Computers cannot directly execute programs expressed in a programming language. The internal representation used by computers for data and operations consists purely of a long sequence of "on" and "off" signals, or binary code.
TODO: FILL IN
Taxonomies of programming languages
It is difficult to design a single overarching classification scheme for programming languages. Unlike the Darwinian evolution of biological species, any given programming language does not usually have a single ancestor language. More commonly, languages arise by combining the elements of several predecessor languages with new ideas in circulation at the time. Ideas that originate in one language will diffuse throughout a family of related languages, and then leap suddenly across familial gaps to appear in an entirely different family.
The task is further complicated by the fact that languages can be classified along multiple axes. For example, Java is both an object-oriented language (because it encourages object-oriented organization) and a concurrent language (because it contains built-in constructs for running multiple threads in parallel). Python is an object-oriented scripting language.
This section presents two taxonomies of programming languages: a classification by programming paradigm and a classification by intended domain of use.
See also: Curly brace family
Classification by programming paradigm
Procedural languages
ADT-based languages: CLU?
Object-oriented languages
CLOS, Dylan, Self, Cecil, BETA
See also: Scandinavian school of object-oriented programming
Functional languages
Logic and constraint languages
Logical languages: Prolog formulates data and the program evaluation mechanism as a special form of mathematical logic known as Horn logic and a general proving mechanism called logical resolution.
also called declarative languages or purely declarative languages
Prolog, Concurrent Prolog, CLP family
Multi-paradigm languages
Procedural languages with an object system grafted on top: Ada, C++, Python, Oberon, Modula-3, Ada95
Functional/OO hybrids: OCaml
Languages with an embedded constraint/logic programming subset: Kaleidoscope
Machine code, assembly, and compiler intermediate forms
LEFT OFF HERE
Machine language is code that is directly executable on a hardware processor, and consists of a chunk of binary data. Most people do not classify machine language as a programming language, although
Its scope is architecture-dependent. It is typically formulated as numbers expressed in octal or hexadecimal. Each group of numbers is associated with particular fundamental operations of the hardware. The activation of specific wires and logic controls the computation of the computer.
Assemblers: Assemblers are almost always directly tied to a machine language. Assembler allows these machine instructions to be written in a form readable by humans. Assembler allows a program to use symbolic addresses which become absolute addresses calculated by the assembler. Most assemblers also allow for macros and symbolic constants as well.
Classification by intended domain of use
Foundational languages (core languages, calculi)
Systems languages
Scripting or embedded languages
ACS, ASP, AppleScript, Awk, BeanShell (scripting for Java), bash, Brain, CobolScript, csh, Dylan, E, Escapade (server side scripting), Euphoria, Groovy, Guile, ICI, IRC script, JavaScript (ECMAScript), JCL, Jython, ksh, Lua, mIRC script, Miva, MUMPS, ObjectRexx,Perl,PHP, Pike, Pliant, Python, QuakeC, REBOL, REXX, Ruby, Scheme, ScriptBasic, sh, Shorthand Language, Simkin, Tcl, UnrealScript, VBScript, Visual DialogScript, ZZT-oop,
Domain-specific languages
An important class of domain-specific languages are the database manipulation languages. SQL
... provide powerful ways of searching and manipulating the relations that have been described as entity relationship tables which map one set of things into other sets.
PaulFord 08:37, 11 Mar 2004 (UTC): Just wrote Domain-specific language before I looked at this rewrite page; perhaps it could be useful to you.
Educational languages
Concurrent and distributed languages
Concurrent Pascal (by Brinch-Hansen), Occam, Pict, SR, Java, Erlang, Joule, CORBA
Commonly Used Languages
The following languages are used by several hundred thousand to several million programmers worldwide:
- various forms of assembly language
- C
- C++
- COBOL
- FORTRAN
- Delphi
- Java
- Perl
- Python
- Visual Basic
See also the alphabetical and chronological lists of programming languages.