Computing & Software Codexery

Programming language

Engineered languages for expressing computer programs.

Programming language

A programming language is an engineered language for expressing computer programs, typically allowing software to be written in a human readable manner. The design of programming languages has been strongly influenced by computer architecture, with most imperative languages designed around the ubiquitous von Neumann architecture. While early programming languages were closely tied to the hardware, modern languages often hide hardware details via abstraction in an effort to enable better software with less effort.

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?

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

Comments

Loading…
Open in the interactive codex →