Programming language
Engineered languages for expressing computer programs.
A programming language is a constructed system for writing computer programs, designed so that humans can read and understand the code. The way these languages are built has been heavily shaped by computer hardware, especially the von Neumann architecture, which most imperative languages follow. Early languages were very close to the machine’s hardware, but modern ones tend to hide those details through abstraction, aiming to make software development easier and more effective.
To run a program, you need an implementation. The two main methods are compilation, where the program is translated into machine code before it runs, and interpretation, where the program is executed directly. Some implementations blend these approaches, using techniques like just-in-time compilation or bytecode interpreters.
Programming languages share some traits with natural languages—they allow people to communicate ideas, and programs are generally readable and can express complex concepts. However, the ideas they can convey are limited to computational tasks. The term “computer language” is sometimes used as a synonym for programming language, but some argue they are different. For instance, some see programming languages as a subset of computer languages, while others use “computer language” for computing-related languages that aren’t programming languages. Another view holds that a programming language is a theoretical tool for programming an abstract machine, and a computer language is the part of it that runs on actual hardware with finite resources. John C. Reynolds argues that formal specification languages are programming languages, just like those meant for execution. He also contends that any textual or graphical input format that affects a computer’s behavior—even if not Turing-complete—qualifies as a programming language, and that ignoring this leads to many flaws in input formats.
The first programmable computers appeared in the 1940s, along with the earliest programming languages. These were first-generation languages, or machine language—simple instructions the processor could execute directly. Such code was hard to debug and couldn’t be moved between different computers. Assembly languages (second-generation) came next, making programs easier for humans to read, but they still weren’t portable. At first, hardware was expensive and scarce, while human labor was cheap, so languages that were cumbersome but efficient—close to the hardware—were preferred. The shift came with high-level languages (third-generation), which hid hardware details and focused on expressing algorithms in a more human-friendly way. For example, arithmetic could be written symbolically and then translated into machine code. Fortran, often seen as the first compiled high-level language, appeared in 1957 and remains in use today.
Around 1960, the first mainframes—expensive, general-purpose computers—emerged, operated only by professionals. Programs and data were fed in via punch cards, with no way to add input while running, so languages from this era were designed for minimal interaction. After the microprocessor was invented, computers became much cheaper in the 1970s, and new models allowed more user interaction, which newer languages supported. Lisp, implemented in 1958, was the first functional programming language. Unlike Fortran, it supported recursion and conditional expressions, and introduced dynamic memory management with automatic garbage collection. For decades, Lisp dominated artificial intelligence. In 1978, another functional language, ML, brought inferred types and polymorphic parameters. ALGOL, released in 1958 and 1960, became the standard for describing algorithms in computing literature. Though not a commercial success, most popular imperative languages—including C, Pascal, Ada, C++, Java, and C#—trace back to ALGOL 60. Its innovations included greater portability and the first use of context-free BNF grammar. Simula, the first language with object-oriented programming (subtypes, dynamic dispatch, inheritance), also came from ALGOL and found commercial success. C, another ALGOL descendant, remains popular into the 21st century. It allows low-level machine operations, and its power and efficiency—partly from flexible pointer operations—come at the cost of making correct code harder to write. Prolog, designed in 1972, was the first logic programming language, using formal logic notation. In logic programming, the programmer states a desired result, and the interpreter figures out how to achieve it.
- field
- Computer science
- known_for
- Expressing computer programs in a human-readable manner
- first_object_oriented_language
- Simula
Lore & Background
The first programmable computers were invented during the 1940s, and with them, the first programming languages. The earliest computers were programmed in first-generation programming languages (1GLs), machine language, which was difficult to debug and not portable. Assembly languages (second-generation programming languages—2GLs) were invented to make programs easier to understand for humans, although they did not increase portability. Initially, hardware resources were scarce and expensive, so cumbersome languages closer to the hardware were favored. The introduction of high-level programming languages (third-generation programming languages—3GLs) revolutionized programming by abstracting away hardware details. Around 1960, the first mainframes were developed, operated by professionals using punch cards, leading to languages designed for minimal interaction. After the microprocessor, computers in the 1970s became cheaper and allowed more user interaction. Simula was the first language to support object-oriented programming. C, another ALGOL descendant, allows access to lower-level machine operations. During the 1980s, the personal computer transformed programming language roles. New languages included C++, a superset of C supporting classes and inheritance. Ada introduced support for concurrency. In the 1990s, the Internet led to languages like Java, designed for portability and security, and dynamically typed scripting languages like Python, JavaScript, PHP, and Ruby. After 2010, languages like Rust, Go, Swift, Zig, and Carbon competed for performance-critical software. Some new languages are classified as visual programming languages like Scratch and LabVIEW.
Reader's Guide
Programming languages are fundamental to computing, enabling humans to communicate instructions to computers in a readable form. Their evolution reflects changes in hardware and user needs: from machine code and assembly languages tied to specific machines, to high-level languages that abstract hardware details, allowing more complex software to be developed with less effort. Later, languages like Lisp and ML advanced functional programming, while ALGOL influenced most imperative languages. Simula pioneered object-oriented programming, and Prolog introduced logic programming. The 1980s saw languages like C++ and Ada, the latter adding concurrency support. The Internet era brought Java for portability and scripting languages for rapid development. Recent languages focus on performance and safety, competing with C. Visual programming languages like Scratch and LabVIEW represent another trend. The definition of a programming language remains debated, with some arguing it includes any formal specification language affecting computer behavior, even if not Turing-complete. Programming languages continue to shape software development, balancing human readability, hardware efficiency, and abstraction.
Did You Know?
- The first programmable computers were invented during the 1940s, and with them, the first programming languages.
Defining the Concept and Distinguishing It from Parallelism
Concurrent computing describes a system property in which multiple computations maintain overlapping lifetimes, each advancing independently without waiting for others to finish. A key point of confusion is its relationship to parallel computing. While both involve multiple processes active during the same period, parallelism demands execution at the identical physical instant—typically across separate processor cores—and is fundamentally impossible on a single-core machine. Concurrency, by contrast, only requires that process lifetimes overlap. On a single core, this is achieved through time-slicing: the scheduler pauses one process mid-execution, resumes another, and later returns to the first. At any given instant only one process is truly executing, yet several are part-way through their work. The practical goal of concurrency is to model real-world situations where events genuinely happen at the same time, such as multiple clients interacting with a server. Structuring software as communicating concurrent components helps manage complexity even when no parallel hardware exists. The precise ordering of task execution is governed by the scheduling policy, and tasks may run serially, interleaved, or simultaneously depending on the chosen schedule.
The Core Engineering Challenge: Coordinating Shared Resources
The central difficulty in building concurrent systems is concurrency control—guaranteeing that interactions between independent executions proceed in the correct order and that shared resources are accessed safely. Without proper coordination, several well-known failure modes emerge: race conditions, deadlocks, and resource starvation. A classic illustration involves a shared bank balance. If both threads evaluate the sufficiency check before either performs the subtraction, both pass the test and both proceed to debit the account. The combined withdrawal now exceeds the original balance, producing an impossible state. This kind of hazard is precisely what concurrency control mechanisms or non-blocking algorithms are designed to prevent. The broader lesson is that even simple shared-state operations become fragile under concurrent access, and the programmer must explicitly reason about the interleaving of steps that appear atomic in a sequential mental model.
Formal Models and Theoretical Foundations
Dataflow theory subsequently extended these ideas, eventually inspiring hardware architectures built to implement dataflow principles directly. In the late 1970s, process calculi emerged as a powerful tool for algebraic reasoning about interacting components. Two landmark examples are the Calculus of Communicating Systems and Communicating Sequential Processes, both of which provide rigorous frameworks for analyzing how independent processes coordinate. The π-calculus later extended this line of work by adding the ability to reason about systems whose communication topology changes dynamically. Beyond process calculi, Leslie Lamport's TLA+ logic, trace-based mathematical models, and Actor event diagrams have all been developed to describe concurrent system behavior. At the implementation level, software transactional memory adapts the database concept of atomic transactions to memory operations, offering a practical mechanism for managing concurrent access.
Practical Advantages and the Design Paradigm
Concurrent computing is not merely an academic exercise; it delivers concrete engineering benefits. First, when a concurrent algorithm is mapped onto multiple processors, program throughput can scale in proportion to the number of available cores, a relationship captured by Gustafson's law. Second, input/output-intensive programs spend most of their time waiting for external operations to complete; concurrency allows that idle waiting period to be repurposed for other tasks, dramatically improving responsiveness. Third, certain problem domains are naturally structured as sets of independent, communicating activities, making a concurrent decomposition the most faithful and maintainable representation. Multi-version concurrency control in databases is one such example. As a design paradigm, concurrent computing is a form of modular programming: an overall computation is factored into subcomputations that may run independently. Pioneers such as Edsger Dijkstra, Per Brinch Hansen, and C.A.R. Hoare laid the groundwork for this approach. Concurrent processes can ultimately be executed in parallel by assigning each to a separate core or distributing them across a network, bridging the gap between logical structure and physical execution.
Frequently Asked Questions
What exactly is a programming language?
It is a purpose-built, human-readable system of syntax and rules that lets people write instructions a computer can execute. Unlike natural languages, every programming language is deliberately engineered to express logic, data manipulation, and control flow in a structured way.
How does computer architecture shape programming language design?
Most imperative languages were built around the von Neumann model, where instructions and data share a single memory bus, so their syntax mirrors sequential, register-style thinking. Modern languages increasingly hide those hardware details behind abstractions so developers can focus on logic rather than memory layout.
Why do programming languages matter in computing?
They bridge the gap between human thought and machine execution, letting engineers express complex algorithms in readable, maintainable form. Without that layer of abstraction, every piece of software would have to be written in brittle, hardware-specific instructions.
More in Computing & Software 1-22
Spotted an error? Know more?
This is a living reference — every entry is fact-audited, and reader corrections feed straight into our audit queue. Suggest an edit · See this site's audit record
