History of Programming Languages
A programming language is the interface between what an engineer intends and what a circuit can execute. Nothing in the physics of a processor requires such a thing. A processor fetches a word, decodes it, and acts on it, and the pattern of bits in that word is the only instruction it understands. Everything above that pattern exists because human beings could not produce correct programs at the scale the hardware made possible, and every generation of language since 1950 has been an attempt to close the gap between a machine that counts in binary and an engineer who thinks in signals, states, and equations.
This history is therefore best read from the hardware side. Two questions recur at every step: what did the machine make necessary, and what did the language make possible. The answers are usually economic rather than aesthetic. In the middle 1950s a large computer rented for more per month than a programmer earned in a year, so a language that wasted cycles was not merely inelegant but unaffordable, and the first high-level language had to prove it could match hand-written code before anyone would use it. By the middle 1990s the ratio had inverted so completely that engineers deliberately chose interpreters running hundreds of times slower than compiled code, because the cycles were nearly free and the engineering hours were not. The same trade, priced differently, explains most of what follows.
Two companion pages on this site cover parts of this ground and are not repeated here. The article on computer industry origins establishes the beginning of the story between 1945 and 1960: machine code, the first assemblers, and the arrival of FORTRAN, COBOL, ALGOL, and LISP. The article on operating systems and software standards covers the rewriting of Unix in C in 1973 and the portability argument that followed from it. This page takes the language line as its own subject and carries it from the stored program to the present argument about memory safety.
One caution about the record. A language can be dated to a design memorandum, a published specification, a working implementation, or a commercial release, with years separating them, and attributions are contested more often than popular accounts admit. Where the record is genuinely ambiguous below, the weaker claim is stated instead of the confident one.
Machine Code, Assemblers, and the Cost of Coding
The stored-program design that spread after 1945 placed instructions and data in the same memory. The immediate consequence was practical: a program could be loaded and replaced without rewiring a machine. The deeper consequence was that a program became an ordinary array of words, which meant that a program could read, modify, and write another program. Every translator, assembler, compiler, linker, and synthesis tool described in this article depends on that single property.
The Clerical View of Coding
Early practice did not treat the writing of instructions as intellectual work. The design of an algorithm was called planning and was performed by mathematicians; the conversion of that plan into machine instructions was called coding and was regarded as transcription. The division was mistaken, and it had lasting effects on who received credit for early software.
Konrad Zuse designed a complete high-level notation, Plankalkül, around 1945, with data structures, assignment, and conditional execution. It was not published in full until 1972 and had no working implementation for decades, so it influenced nothing that followed. It stands as evidence that the idea of a language above the machine occurred to people well before any machine could support one.
Symbolic Assembly and the Machine Underneath
Assemblers answered that difficulty by letting the programmer write symbolic names for operations and for memory locations and by recomputing the addresses on every assembly. Contemporary objections were serious rather than foolish: an assembler consumed expensive machine time to produce something the programmer could have produced with a pencil, and on installations billed by the hour that cost was visible on an invoice.
The first assemblers also did work that no reasonable programmer would want to do. The IBM 650 stored its program on a rotating magnetic drum, and the time to fetch the next instruction depended on how far the drum had turned since the last one. Placing consecutive instructions in consecutive drum locations was therefore the worst possible arrangement. The Symbolic Optimal Assembly Program, universally called SOAP, chose drum addresses so that the next instruction arrived under the read head at approximately the moment it was needed. Here, at the very beginning, a translator already understood a property of the hardware that the engineer using it was relieved of tracking.
Parallel work in Britain produced the autocodes. Alick Glennie wrote the first, for the Manchester Mark 1, in 1952; it is sometimes described as the first compiled language, though its influence on other users at Manchester was negligible. Tony Brooker's Mark 1 Autocode of 1955 mattered more, because it supplied floating-point arithmetic and concealed the two-level store, removing the two burdens that had dominated Mark 1 programming.
Interpretive systems occupied the same period. John Mauchly's Short Code of 1949 evaluated algebraic expressions on the BINAC and UNIVAC line at a heavy speed penalty, and John Backus wrote Speedcoding for the IBM 701 in 1953, giving that machine floating-point arithmetic it did not possess in hardware at a cost of roughly an order of magnitude in speed. Grace Hopper's A-0 system of 1952 assembled programs from a library of subroutines, and she called it a compiler in the older sense of one who gathers material rather than in the modern sense of a translator.
Macros, Relocation, and the First Reusable Software
Assemblers grew two features that outlived them. The macro let a programmer name a parameterized block of instructions and expand it wherever the name appeared, with conditional assembly deciding which variant to emit. That is source-text generation, and it established the habit of writing programs that write programs. Relocatable object code let a routine be assembled once, without knowing where in memory it would finally sit, and a linker later resolved its references and fixed its address.
The combination produced the subroutine library and the first genuinely reusable software, circulated between installations by user groups such as SHARE. That object-file and linker model is still the shape of every embedded toolchain: an engineer compiling firmware today produces relocatable objects, links them against libraries, and directs a linker script to place code in flash and variables in RAM.
Why Assembly Never Went Away
Assembly language remains in production use for work that no high-level language can express. Startup code must set a stack pointer and clear the uninitialized data section before any compiled function can safely run. Interrupt prologues and the context switch inside a real-time kernel manipulate registers the calling convention does not expose. Bit-banged protocols need loops whose cycle counts are exact, and the C abstract machine has no concept of a cycle. Cryptographic routines must run in constant time regardless of the data, which means suppressing exactly the optimizations a compiler exists to perform.
FORTRAN and the Efficiency Argument
John Backus proposed a practical alternative to assembly language to his superiors at IBM in late 1953. A draft specification for the IBM Mathematical Formula Translating System was complete by November 1954, the first manual appeared in October 1956, and the first compiler was delivered in April 1957. A team of about a dozen people spent the intervening years on it, and nearly all of that effort went into the compiler rather than the language.
That distribution of effort is the point. The language itself is unremarkable and was designed quickly; the difficulty was proving that a translated program could be as fast as a hand-written one. Backus and his team therefore built an optimizer at a level of sophistication that would not be matched for years, performing index-register allocation, common subexpression elimination, and a flow analysis that estimated how often each part of a program would execute. When the compiler shipped and the generated code proved competitive with careful hand coding, the burden of proof shifted permanently. After 1957 the question was no longer whether a compiler could be used, but where it could not.
The language bears the marks of the machine it was written for. The IBM 704 had three index registers and floating-point hardware, and FORTRAN's DO loop maps directly onto index-register operation. The arithmetic IF sent control to one of three destinations according to whether an expression was negative, zero, or positive, because that is what a machine comparison produced. The fixed column layout, with statement numbers in columns one through five and a continuation marker in column six, came from the eighty-column punched card, and it survived into FORTRAN 77 long after cards had disappeared from machine rooms.
FORTRAN 66, standardized as ASA X3.9-1966, is generally described as the first national standard for a programming language. ANSI X3.9-1978 defined FORTRAN 77, after which the language moved to international standardization as Fortran 90, published as ISO/IEC 1539:1991, with revisions in 1997, 2004, 2010, 2018, and 2023.
The language persists in electronics work for a specific technical reason as well as inertia. Fortran's rules forbid the aliasing of formal array arguments, so a compiler may assume that two arrays passed to a subroutine do not overlap and may therefore reorder and vectorize loops that a C compiler must treat conservatively. That single semantic difference underlies much of Fortran's reputation for numerical speed, and C acknowledged it by adding the restrict qualifier in its 1999 revision. Electromagnetic and device-simulation codes written in Fortran remain in service; the Numerical Electromagnetics Code used for antenna modeling is a well-known example still applied to practical radio work.
COBOL, Readability, and Decimal Arithmetic
The Conference on Data Systems Languages, formed at a meeting at the Pentagon in May 1959, produced a specification in December of that year, and the government published it in 1960. That much is covered in this site's account of the period. What matters for the language line is the argument COBOL made, which was not about efficiency at all.
The argument was that a program is read far more often than it is written, and mostly by people who did not write it. COBOL therefore adopted a verbose, English-like syntax in which a computation reads as a sentence, on the theory that a manager or an auditor could follow a payroll calculation without being a programmer. The claim proved partly true and has been contested ever since. At the level of a single statement COBOL is genuinely legible; at the level of a program of a hundred thousand lines the verbosity works against comprehension, because the reader must process far more text to find the logic. The unresolved tension between local clarity and global structure is one of the permanent arguments of language design, and COBOL stated it first.
The DATA DIVISION was the more durable contribution. COBOL separated the description of data from the description of processing and gave the programmer a PICTURE clause that specified the layout of a record field by field, character by character. That is a declarative data description language embedded inside a programming language, and its descendants are everywhere in electronics: the C structure that overlays a peripheral register block, the packed binary layout of a communication protocol, and the register-map header generated from a vendor description file all do the same job.
COBOL also insisted on exact decimal arithmetic, and the hardware answered. A tenth cannot be represented exactly in binary floating point, so a financial calculation performed in binary accumulates errors that an auditor will not accept. COBOL specified decimal arithmetic with declared precision, and IBM's System/360 accordingly implemented packed-decimal instructions in hardware. Decimal formats and instructions remain in the z/Architecture line today, and the 2008 revision of IEEE 754 added decimal floating-point formats to the general standard for floating-point arithmetic. A language requirement drove an instruction set feature, which is worth noting because the influence is usually assumed to run the other way.
COBOL became an American national standard as ANSI X3.23-1968, was revised in 1974 and 1985, and received ISO revisions in 2002 and 2014. It survives in banking, insurance, and government systems more than sixty years on. Estimates of how much of the world's transaction processing still passes through COBOL circulate widely, but they originate almost entirely with vendors selling migration or maintenance services and should be treated accordingly. What is not in doubt is that the Year 2000 remediation effort was substantially an exercise in reading COBOL, and that the code it repaired is largely still running.
ALGOL, Backus-Naur Form, and the Machine Built to Run It
ALGOL was the first language designed by an international committee with no manufacturer's machine in view. A meeting in Zurich in 1958 produced ALGOL 58, initially called the International Algebraic Language, and a meeting in Paris in January 1960 produced the language that mattered. The Report on the Algorithmic Language ALGOL 60, edited by Peter Naur, appeared in the Communications of the ACM in May 1960, with a revised report in 1963.
Commercially, ALGOL 60 failed in the United States, where FORTRAN was entrenched and IBM had no reason to promote a rival. Technically, it supplied the vocabulary that nearly every later language uses. Block structure with lexical scope, the compound statement, the distinction between declaration and statement, recursion, and formally specified parameter passing all reached the mainstream through ALGOL 60. C. A. R. Hoare's often-quoted judgment from 1973 was that it was a language so far ahead of its time that it improved not only on its predecessors but on nearly all of its successors.
Its most consequential feature was not a language feature at all but a piece of notation. Backus presented a metalanguage for describing the syntax of ALGOL 58 at a Paris conference in 1959; Naur adapted it for the ALGOL 60 report; Donald Knuth later proposed the name Backus-Naur form. For the first time the syntax of a programming language was defined by a finite set of production rules rather than by examples and prose. The effect was to convert parsing from a craft into an engineering problem with a literature and a theory behind it, and parser generators followed within fifteen years.
That notation is now part of the working equipment of electronics. The grammars of Verilog, VHDL, and SystemVerilog are specified in it. So are netlist and simulation input formats, configuration languages, and the message formats of communication protocols, where the augmented form defined in RFC 5234 is the usual dialect. An engineer reading the syntax section of a hardware standard is reading a direct descendant of a 1959 conference paper.
Recursion had a hardware consequence as well. A language that permits a procedure to call itself requires a stack of activation records, and Burroughs built the B5000, delivered in the early 1960s, as a stack machine designed around ALGOL. Its system software was written in an ALGOL dialect, and Burroughs did not supply an assembler to its customers at all, which was a radical position at a time when serious programming meant assembly language. The line demonstrated that a machine could be designed for a language rather than the reverse.
The committee's successor effort, ALGOL 68, aimed at far greater generality and produced a specification written in a formalism most readers found impenetrable; a minority of the working group published a dissenting report objecting that the language was too complex to implement or teach. Niklaus Wirth, who had proposed a simpler alternative, left the effort and built Pascal instead.
LISP, Garbage Collection, and Hardware Built for a Language
John McCarthy began work on LISP at MIT in 1958, and his paper describing recursive functions of symbolic expressions appeared in April 1960. The language was intended for symbolic rather than numerical computation, and it took an approach almost opposite to FORTRAN's. Data were lists; programs were lists; the same notation described both.
That last property, later called homoiconicity, gives LISP its distinctive power. Because a program is an ordinary data structure, a program can construct and transform other programs with the same operations it uses on any other data. McCarthy had written a definition of the language in terms of itself as a mathematical exercise; Steve Russell observed that the definition could simply be implemented, and the result was an interpreter that nobody had planned to build.
LISP also introduced automatic memory management. Programs that build and discard list structure continuously cannot practicably free memory by hand, so the system reclaimed unreachable memory itself. Garbage collection is now ordinary in Java, Python, C#, Go, and JavaScript, and it is one of the reasons those languages are largely absent from hard real-time control. A collector runs when it must, not when the engineer chooses, and a control loop with a deadline measured in microseconds cannot accommodate an unpredictable pause. Real-time collectors exist and bound their pauses, at a cost in throughput and complexity, but the difficulty is structural rather than a defect of any particular implementation.
The clearest case in this history of a language justifying custom silicon is the LISP machine. Interpreting list structure on a conventional processor spends most of its time checking type tags and chasing pointers, so researchers at MIT built machines whose hardware checked tags, whose memory was organized for list structure, and whose microcode assisted garbage collection. Symbolics and Lisp Machines Incorporated commercialized the design around 1980, and Xerox produced a parallel line for Interlisp. Within a decade the machines were gone. General-purpose microprocessors improved at a rate that no specialized workstation vendor could match, compiled Lisp on ordinary hardware became competitive, and the contraction in artificial-intelligence funding removed the customers. The episode is a compact statement of a rule that has held ever since: specialized hardware for a general-purpose workload survives only while the commodity part cannot catch up.
What survived is the ideas. Conditional expressions, recursion, dynamic typing, garbage collection, the read-evaluate-print loop, and the interactive development environment all entered general practice from this line, and Lisp dialects still run inside working tools such as the Emacs editor and AutoCAD.
BASIC, Time-Sharing, and Programming Made Ordinary
John Kemeny and Thomas Kurtz designed BASIC at Dartmouth College so that students who were not scientists or engineers could use a computer. The first program ran on May 1, 1964, on a GE-225 under the Dartmouth Time-Sharing System, and the two were designed together. The language and the operating system were a single project because the goal was access rather than expressiveness: a student was to sit at a teletype, type a program, and see a result within seconds.
The design follows from that goal. Line numbers served as editor addresses on a printing terminal with no screen, so that a correction meant retyping one numbered line. The interpreter reported errors immediately and in plain language. The language was small enough that a beginner could hold all of it in mind, which was the property Dartmouth cared about and which every later criticism of BASIC underestimated.
Minicomputer vendors adopted BASIC because it made a machine usable on the day it arrived. Digital Equipment Corporation and Hewlett-Packard shipped interpreters with their systems, and the language became the working notation of the laboratory. The combination that mattered for electronics was BASIC with an instrument bus. Hewlett-Packard's desktop computers drove instruments over the HP-IB interface, standardized as IEEE 488 in 1975, and for roughly two decades an automated test bench in a development laboratory was very likely a BASIC program issuing commands over that bus. The engineer writing it was not a programmer and did not need to become one, which was exactly the Dartmouth argument transplanted.
The microcomputer generation made BASIC universal. Bill Gates, Paul Allen, and Monte Davidoff wrote an interpreter for the Altair 8800 in 1975, and by 1978 Microsoft BASIC was a de facto standard. Practically every home computer of the 1980s carried an interpreter in read-only memory, and the reason was economic rather than pedagogical: a mask ROM was the cheapest user interface a manufacturer could ship, and the interpreter doubled as the command shell, the editor, and the program loader. Turning the machine on produced a prompt at which the user could immediately type a program.
Two consequences followed for electronics. The first is that a large fraction of the engineers who entered the industry in the 1980s learned to program on a machine that offered them nothing else. The second is subtler: the PEEK and POKE operations that these interpreters provided let an untrained user read and write arbitrary memory addresses, and on machines where display hardware, sound generators, and input ports were memory-mapped, that was a first lesson in memory-mapped input and output delivered by accident.
The academic judgment was severe, and Edsger Dijkstra's remark that exposure to BASIC mutilated the mind beyond hope of regeneration is the best-known example. The criticism had substance, since unrestricted branching between numbered lines produces exactly the structure that structured programming was formulated to prevent. Structured dialects answered it, including Kemeny and Kurtz's own True BASIC, and Visual Basic gave the language a second commercial life from 1991.
The Microprocessor's Own Languages
The first microprocessors arrived with no software of any kind. A 4004 or an 8008 offered a few kilobytes of memory, an awkward instruction set, and no development tools, so early work was cross-developed on a minicomputer and the result was burned into a programmable read-only memory and tested in hardware. The languages that took hold on these parts were shaped by that poverty.
Gary Kildall wrote PL/M for Intel in 1973, first for the 8008 and then for the 8080. It is generally described as the first high-level language for microprocessors, and it was designed as a systems language: structured control flow and typed data, with direct access to memory addresses and hardware registers retained rather than hidden. Kildall used it to write the disk operating system that became CP/M, and PL/M remained the implementation language for the parts of CP/M that were not assembly. The claim made for it at the time, that a program of roughly the same size and speed as assembly could be written in about a tenth of the time, is the same claim FORTRAN had made fifteen years earlier, restated for a processor that cost a few hundred dollars instead of a few hundred thousand.
Forth took a different route to the same constraint. Charles Moore had developed the system continuously since 1968, and it appeared publicly around 1970; he and Elizabeth Rather developed it further at the National Radio Astronomy Observatory. Forth is stack-based and extensible: the programmer defines words in terms of existing words, and a program is a vocabulary rather than a hierarchy. Compiled to threaded code, it produced extremely compact programs, and a complete environment including compiler, editor, and application fitted in the memory of an eight-bit machine. It became a working tool of instrumentation and astronomy, and it embedded itself in boot firmware: Open Firmware boot ROMs used by Apple, Sun, IBM, and the OLPC XO-1 contain a Forth interpreter, standardized as IEEE 1275-1994. Forth has also flown, including on the Philae lander.
Assembly nonetheless remained the dominant production language for microcontroller work into the 1990s, and the reason was architectural rather than cultural. Eight-bit parts such as the 8051 and the PIC families are actively hostile to a compiler: they have hardware call stacks of limited depth, banked memory that requires explicit switching, accumulator-centered instruction sets with almost no general registers, and separate address spaces for code and data. A C compiler for such a part generates code an experienced programmer can beat by a wide margin. The transition to compiled firmware followed the arrival of parts a compiler could serve well, with linear address spaces and register files worth allocating, first in the 68000 family and then decisively with ARM.
C and the Systems Programming Language
C descends from a short line. Martin Richards designed BCPL in 1967, a typeless language in which every value was a machine word. Ken Thompson reduced it to B at Bell Laboratories around 1969 for the PDP-7. Dennis Ritchie began adding types and structures in 1971, and by 1972 the result was called C.
The design decision that defines C is that its type system describes machine storage rather than mathematical objects. A character is the smallest addressable unit, an integer is whatever the machine's natural word supports within stated minimums, a pointer is an address with a type attached, and an array name yields a pointer to its first element. There is no bounds checking because the target machines did not check bounds and a software check costs cycles the language was unwilling to spend. This is not an oversight in the design; it is the design, and it is the origin of the argument taken up at the end of this article.
A frequent claim is that C's increment and decrement operators reflect PDP-11 addressing modes. The claim does not survive the dates, since both operators were present in B on the PDP-7. What is fair to say is that the language exposes a model of memory as a flat array of addressable bytes, which matched the minicomputers of its era and matches most machines since.
Kernighan and Ritchie published the first edition of their book in 1978, which served as the definition for a decade. Formal standardization produced ANSI X3.159-1989, adopted internationally as ISO/IEC 9899:1990. The consequences of C for hardware vendors, and the 1977 port of Unix to a deliberately dissimilar machine that proved the portability argument, are treated on this site's page on operating systems and software standards and are not restated here.
What each later revision gave to electronics work is worth stating specifically. C99, published as ISO/IEC 9899:1999, standardized fixed-width integer types in <stdint.h>, which replaced a generation of incompatible per-project typedefs and made a peripheral register header portable for the first time; it also added the restrict qualifier, recovering some of the aliasing freedom Fortran compilers had always enjoyed. C11, published in December 2011, added atomic types, a threading interface, and a memory model, converting concurrent programming from folklore about volatile variables into something a standard actually specified. C17 was a defect-repair revision published as ISO/IEC 9899:2018. C23, published in October 2024 as ISO/IEC 9899:2024, added binary integer literals, a typed null pointer constant, compile-time constant objects, and a standard header of bit-manipulation utilities, most of which formalize what embedded programmers had done with macros for thirty years.
Two features carry most of the weight in firmware. The standard distinguishes hosted implementations, which assume an operating system and a full library, from freestanding implementations, which do not, and a microcontroller runs the latter. The volatile qualifier tells the compiler that an object may change outside the program's control and that accesses to it must not be optimized away or reordered, which is what makes a memory-mapped peripheral register usable from a high-level language at all. The hazards are equally specific: bitfield order and packing are implementation-defined, so a structure overlaid on a hardware register may lay out differently under a different compiler; integer promotion silently widens small types; and signed integer overflow is undefined behavior that modern optimizers actively exploit. Present-day practice is covered on this site's page on embedded C programming.
Undefined behavior deserves a plain statement, because it is the hinge of the modern argument. It exists so that a compiler need not emit code for cases the standard declines to define, which lets the compiler assume they never occur and optimize accordingly. That assumption buys speed and costs safety, and the exchange rate has moved steadily against the language as the value of a cycle has fallen and the cost of a vulnerability has risen.
Discipline by Design: Pascal, Modula-2, and Ada
Niklaus Wirth designed Pascal at ETH Zurich in 1970 as a reaction to ALGOL 68. It was deliberately small, strongly typed, and structured so that a single-pass compiler could handle it, and it was intended for teaching. Its influence on practice was greater than its commercial adoption, because a generation of computer science students learned structured programming in it.
The implementation that mattered most for hardware was Kenneth Bowles's UCSD Pascal, from 1977. It compiled not to machine code but to p-code, a compact instruction set for an idealized stack machine, and executed the p-code with a small interpreter. Porting the system to a new processor meant writing an interpreter of a few kilobytes rather than a code generator. Portability purchased with a virtual machine is one of the field's durable ideas, and it returns in the Java virtual machine, in the .NET common language runtime, in the bytecode of MicroPython, and in WebAssembly. It was first made practical on eight-bit microcomputers with sixty-four kilobytes of memory.
Borland's Turbo Pascal of 1983 supplied an integrated compiler, editor, and debugger that ran on a CP/M machine and sold for a fraction of the price of professional tools, demonstrating that the barrier to compiled languages had been the price and bulk of the toolchain rather than the languages. Brian Kernighan's 1981 critique catalogued Pascal's real defects for systems work, chief among them array types whose size was part of the type and the absence of separate compilation. Wirth had already answered both in Modula-2 in 1978, which introduced modules with explicit interfaces, and later in Oberon in 1986.
Ada came from a procurement problem. The United States Department of Defense formed the Higher Order Language Working Group in 1975 after finding that its embedded weapons systems were programmed in several hundred different languages and dialects, each with its own tools, training, and maintenance burden. The group wrote a sequence of requirements documents named Strawman, Woodenman, Tinman, Ironman, and finally Steelman in 1978, then solicited designs. Four contractors submitted proposals identified only by color so that evaluators would not know their source: Red from Intermetrics, Green from CII Honeywell Bull under Jean Ichbiah, Blue from SofTech, and Yellow from SRI International. Red and Green advanced in April 1978, and Green won in May 1979.
The standard appeared as MIL-STD-1815 on December 10, 1980. Both the number and the date refer to Ada Lovelace, born in 1815 on the tenth of December. ANSI/MIL-STD-1815A followed in 1983, and international standardization as ISO 8652 in 1987. Ada 95 was the first internationally standardized object-oriented language, and revisions followed as Ada 2005, Ada 2012, and Ada 2022, published as ISO/IEC 8652:2023.
Ada repays attention from electronics engineers for a feature that has no equivalent in C. Representation clauses let a program state, in the language and portably specified, the exact bit position and length of every field of a record, the endianness of the record, and the machine address at which an object resides. Mapping a structure onto a hardware register is therefore a defined operation rather than a bet on a particular compiler's bitfield layout. Ada also supports subtypes constrained to a numeric range with checks the compiler inserts, fixed-point types with a declared resolution, and a task construct with a defined synchronization mechanism, which put concurrency in the language at a time when the alternative was an operating system call.
The mandate is the part of the story usually told badly. Department of Defense policy required Ada for defense software, reaching its strongest form in the early 1990s, and was effectively removed in 1997 as the department shifted toward commercial off-the-shelf software. The mandate produced compliance without enthusiasm, and its removal caused a sharp decline in new Ada projects outside the domains where the language's properties actually paid.
The failure of Ariane 501 on June 4, 1996, is often cited against Ada and should not be. The inertial reference system carried alignment code reused from Ariane 4 that kept running for about forty seconds after liftoff, serving no purpose on the new vehicle, and Ariane 5's trajectory produced a horizontal-bias value that overflowed a conversion from a sixty-four-bit floating-point value to a sixteen-bit signed integer. The inquiry board led by Jacques-Louis Lions found that only four of seven critical variables had been protected against overflow, because protecting all of them would have exceeded a processor workload target, and that the specification required a processor to shut down when an exception was detected. The language detected the error exactly as designed; what failed was the system-level decision about what to do with the detection. A language can find an error, but only a system design can decide what an error means.
SPARK, a subset of Ada restricted so that programs can be formally proved to satisfy contracts written in the language, carries the discipline argument to its conclusion and is used in avionics and rail signaling. Ada itself persists in avionics, air traffic management, rail interlocking, and space systems, which are precisely the domains where the cost of a defect exceeds the cost of the language's strictness.
Object Orientation from Simula to Java
Ole-Johan Dahl and Kristen Nygaard began collaborating at the Norwegian Computing Center in January 1962 on a language for discrete event simulation. Simula I was established that year, and Simula 67, presented at an IFIP working conference in May 1967 and standardized in February 1968, introduced objects and classes, inheritance and subclasses, virtual procedures, coroutines, and garbage collection. The two received the IEEE John von Neumann Medal in 2001 and the A. M. Turing Award for 2001, presented in 2002, the year both died.
It is worth asking why simulation produced object orientation, because the answer explains why the idea travels so well into hardware. To simulate a system of interacting physical entities, the natural program structure is one object per entity, each holding its own state and responding to events through a defined interface. That is a modeling idea before it is a software-engineering idea, and it is the model an electronics engineer already carries: a design is a set of concurrent blocks with internal state and specified ports. The same intuition reappears, independently, in the module construct of every hardware description language.
Alan Kay, Dan Ingalls, Adele Goldberg, and colleagues at Xerox PARC pushed the idea to its limit in Smalltalk through the 1970s, in which everything is an object, all computation is message sending, and development happens in a persistent image rather than a file-and-compile cycle. Byte magazine devoted its August 1981 issue to the system, which is how most of the industry first encountered it. The bitmapped display and the mouse-driven interface came from the same laboratory, and the three ideas travelled together.
Bjarne Stroustrup began work on C with Classes at Bell Laboratories in 1979, wanting Simula's organizing power at C's cost. The name changed to C++ in 1983, the Cfront front end translated the language into C, and the first commercial release and the first edition of the book both appeared in 1985. Standardization produced ISO/IEC 14882:1998, followed by revisions in 2003, 2011, 2014, 2017, 2020, and C++23, published in October 2024. The design principle Stroustrup stated repeatedly is that a program should not pay for a feature it does not use.
Embedded practice was nonetheless slow to accept it, and the objections were concrete rather than conservative. Exceptions require unwinding machinery and non-deterministic time; run-time type information adds tables to a binary with kilobytes to spare; constructors that allocate memory conflict with systems that forbid dynamic allocation after start-up; and templates instantiate once per type and can multiply code size without warning. An industry group in Japan defined the Embedded C++ subset in the late 1990s to remove those features outright. It never became dominant, and the practice that settled instead was to keep the full language, disable specific features with compiler options, and constrain usage with a coding standard. The AUTOSAR guidelines for C++14 served that purpose in automotive software for years, and their content was carried into MISRA C++:2023.
Java began as an embedded project and is usually remembered as anything but. Sun Microsystems started the Green Project in 1991 to target consumer electronics, and the team built a handheld controller called the Star7 in 1992 to demonstrate a language then named Oak. The set-top box market did not materialize; the language was renamed and released publicly in 1995, and the web carried it. Its embedded descendants nonetheless succeeded in narrow and very large niches, with Java Card running on SIM and payment cards in enormous volumes and Java 2 Micro Edition on feature phones for a decade. The virtual machine model is the UCSD p-System idea at industrial scale, and it carries the same trade: portability purchased with an interpreter, plus a garbage collector that complicates any use with a hard deadline.
Scripting Languages and the Automated Bench
By the late 1980s the arithmetic that governed language choice had reversed. A workstation executed millions of instructions per second, memory was measured in megabytes, and an engineer's hour cost more than any plausible quantity of wasted cycles. Languages appeared that traded execution speed for development speed on purpose, and they were adopted fastest in exactly the work where a program is written once, run occasionally, and modified constantly.
Larry Wall released Perl in 1987 for text processing and system administration. John Ousterhout designed Tcl in 1988 with a different aim: it was meant to be embedded inside an application as its command language, so that a tool could acquire a full scripting interface without its authors designing a language. Paired with the Tk toolkit, it also supplied a way to build graphical interfaces quickly.
That design choice made Tcl the control layer of electronic design automation, which is the least appreciated language fact in modern electronics. Because Tcl was built to be embedded, the major EDA vendors adopted it as the command interface of their synthesis, place-and-route, timing, and verification tools, and complete design flows are written as Tcl scripts. The Synopsys Design Constraints format, which communicates clock definitions, input and output delays, and timing exceptions between tools from different vendors, is a set of Tcl commands. A digital designer at a large company today very likely writes more Tcl in a year than most professional software engineers write in a career, and almost none of that code appears in any survey of language popularity.
Guido van Rossum began Python in December 1989 and released the first version in February 1991, and its rise on the engineering bench has been the most consequential language event of the past two decades. Instrument control moved to Python through libraries that speak SCPI over the VISA interface, so that a test sequence once written in HP BASIC is now a script, and measurement data reduction, automated test frameworks, silicon bring-up scripts, and EDA flow wrappers followed. Machine-learning frameworks show the underlying pattern most clearly: the numerical work happens in compiled and vectorized libraries, and Python only orchestrates. That is the same division of labor a BASIC program calling assembly subroutines used in 1978, at a different scale.
The dynamic languages of 1995 filled in the rest of the landscape. Brendan Eich wrote JavaScript at Netscape that year under severe schedule pressure, and Ruby and PHP appeared alongside it. None was designed for electronics, yet all three now appear in device user interfaces, in configuration tooling, and in the web front ends of instruments and industrial equipment.
The most direct effect on hardware came later. Damien George funded MicroPython through a Kickstarter campaign in 2013 and produced a Python subset, compiler and runtime included, small enough to run on a microcontroller with a few hundred kilobytes of flash. Adafruit's CircuitPython derivative followed in 2017, presenting the device as a removable drive holding an editable source file. A sensor prototype can now be written with no toolchain, no debug probe, and no compile step, and a manufacturer selling a breakout board is expected to publish a Python driver for it. The Arduino platform had made the same argument a decade earlier by a different route: its language is C++ with a library and a small preprocessing step, and its contribution was the toolchain and board bring-up rather than the language, as this site's page on the Arduino ecosystem describes.
Languages That Describe Hardware Rather Than Execute
Everything above concerns languages that describe a sequence of operations. Hardware is not a sequence. A circuit exists all at once, every gate evaluating continuously, and time is a physical quantity rather than a program counter. A language for hardware must therefore make concurrency and time part of its semantics, and running such a program means simulating physical behavior rather than performing a computation. This is a genuine category difference, and treating a hardware description language as a programming language is the most common mistake newcomers make.
VHDL came out of the Very High Speed Integrated Circuit program of the United States Department of Defense in the early 1980s. The department wanted a vendor-neutral way to document the behavior of the integrated circuits it procured, so that a part could be described in a form that survived its manufacturer. The language was a documentation requirement before it was a design tool, which explains its verbosity and its strong typing. It was standardized as IEEE 1076-1987 and revised repeatedly thereafter.
Verilog arrived from the commercial side. Prabhu Goel, Phil Moorby, and Chi-Lai Huang developed it between late 1983 and early 1984 at the company that became Gateway Design Automation, as the input language of a logic simulator. Its syntax deliberately resembles C, because the engineers expected to use it already knew C. Cadence Design Systems acquired Gateway in 1990 and placed the language in the public domain through Open Verilog International, which later became Accellera, and standardization followed as IEEE 1364-1995, with revisions in 2001 and 2005.
Logic synthesis changed what both languages were for. Once a tool could accept a register-transfer-level description and produce a gate netlist, engineers stopped describing circuits they had already designed and started writing descriptions from which circuits would be derived. The industry then had to define a synthesizable subset, because most of what a simulation language can express has no hardware realization: delays, file input and output, unbounded data types, and arbitrary sequential control flow all simulate perfectly and synthesize to nothing. The gap between what simulates correctly and what synthesizes correctly remains the most persistent source of error in digital design, and it exists because the languages were designed for simulation and were later asked to do something else.
SystemVerilog, standardized as IEEE 1800-2005 and merged with Verilog in IEEE 1800-2009, added assertions, constrained random stimulus generation, and functional coverage, with the result that the verification half of the language is now larger than the design half. SystemC provides system-level modeling as a C++ class library standardized as IEEE 1666, and high-level synthesis tools accept C, C++, or SYCL and generate register-transfer-level code, which reopens the argument of 1957 one level up: the tool produces a result quickly, and the engineer asks whether it is as good as a careful designer would have written. This site covers both the hardware description languages and high-level synthesis in detail. Newer projects such as Chisel embed hardware construction in a general-purpose language and emit Verilog, which is the relationship a compiler has to assembly, replayed a level higher.
Two other domain languages show a notation shaped by its users rather than by its machine. IEC 61131-3, first published in December 1993, defines the programming languages of programmable logic controllers: ladder diagram, function block diagram, and sequential function chart as graphical notations and structured text as a textual one, with instruction list deprecated in the 2013 edition. Ladder diagram exists because the controllers it programs replaced relay panels, and the electricians who maintained those panels had to be able to read the software that replaced them. National Instruments took a comparable approach with LabVIEW in 1986, whose G notation makes a program a wiring diagram, matching how an instrumentation engineer already draws a signal path. Both appear again in this site's history of industrial and control electronics.
The Memory-Safety Argument
The current argument in language design returns to the decision C made in 1972. C and C++ permit a program to read and write memory outside the bounds of any object, to use memory after freeing it, and to dereference an invalid pointer, and the results range from a corrupted measurement to a remotely exploitable vulnerability. This is not a defect in the implementations. It follows directly from the choice to omit run-time checks in order to save cycles.
Two measurements shaped the debate. A Microsoft security engineer reported in 2019 that roughly seventy percent of the vulnerabilities the company assigned identifiers to each year were memory-safety issues. The Chromium security team reported in 2020 that roughly seventy percent of serious security bugs in the browser were memory-safety problems. Both figures come from the organizations themselves and describe large bodies of C and C++ maintained by well-resourced teams applying static analysis, fuzzing, and code review. The implication drawn from them is that the defect rate is a property of the languages rather than of the discipline applied to them.
The embedded industry reached the problem first and answered with restriction rather than replacement. The Motor Industry Software Reliability Association published guidelines for the use of C in vehicle-based software in 1998, with 127 rules of which 93 were required and 34 advisory. MISRA C:2004 revised the set to 142 rules. MISRA C:2012 restructured the document into 143 rules and 16 directives and, more importantly, classified each rule by decidability, stating whether a static analyzer can decide compliance and whether the analysis must span translation units. That classification is what made automated checking practical rather than aspirational. Further editions appeared in 2023 and 2025, and MISRA C++ followed the same path, with the 2023 edition carrying in the AUTOSAR C++14 guidance.
The rules forbid the parts of C most likely to produce undefined behavior: dynamic memory allocation after initialization, recursion, most uses of goto, implicit conversions that lose information or change signedness, and any reliance on behavior the standard leaves undefined or unspecified. Compliance is demonstrated with static analysis tools and documented deviations. It is not a legal requirement, but functional safety practice expects it, and both ISO 26262 and IEC 61508 recommend the use of language subsets and coding standards. Expert testimony in the 2013 Oklahoma litigation over unintended acceleration in Toyota vehicles described very large numbers of MISRA C violations in the engine control software, and the episode did more to establish the practice in industry than any standards committee had managed.
Rust represents the other answer, which is to change the language. Graydon Hoare began it as a personal project in 2006, Mozilla sponsored it from 2009, version 1.0 was released on May 15, 2015, and the Rust Foundation was established in February 2021. Its distinguishing mechanism is ownership checked at compile time: each value has one owner, references borrow it under rules the compiler enforces, and the borrow checker rejects programs in which a reference could outlive the data it points to. Memory safety and freedom from data races follow without a garbage collector, which is what makes the language a candidate for work where a collector is unacceptable. The no_std attribute excludes the parts of the standard library that assume an operating system, leaving a core suitable for a microcontroller.
Adoption in systems work has been steady rather than sudden. The Linux kernel accepted infrastructure for Rust in version 6.1 at the end of 2022, with drivers following in later releases; Android has shipped Rust components for several years; and Microsoft has stated that it rewrote portions of Windows components in the language. Embedded support exists for ARM Cortex-M targets through community hardware abstraction crates, and Ferrous Systems states that its Ferrocene toolchain has been qualified against ISO 26262 and IEC 61508, which answers the objection that a safety-critical project cannot use a compiler no certification body has assessed.
Government positions followed the measurements. The National Security Agency published a cybersecurity information sheet titled Software Memory Safety in November 2022, advising a strategic shift away from languages with little inherent memory protection. CISA, the NSA, the FBI, and partner agencies in Australia, Canada, New Zealand, and the United Kingdom published The Case for Memory Safe Roadmaps in December 2023, and the White House Office of the National Cyber Director published Back to the Building Blocks: A Path Toward Secure and Measurable Software in February 2024. None of these documents carries the force of regulation, but procurement follows guidance of this kind eventually.
The counterargument is not weak. The installed base of C is enormous and much of it is correct and running; qualified toolchains, certified libraries, and validated processes exist for C in every safety-critical domain, and requalification under DO-178C or ISO 26262 is expensive and specific to the tool; a rewrite of working code introduces new defects at a rate that is easy to underestimate; and compilers for small or unusual architectures may exist only for C. The realistic path in electronics is incremental, applying the newer language to new components and to the parts of a system most exposed to untrusted input.
There is also a hardware answer, which belongs in this history because it inverts the usual direction. If the language cannot be changed, the machine can be. The CHERI research program extends a processor's memory model with capabilities that carry bounds and permissions in hardware, so that an out-of-bounds access faults regardless of what the source language permits, and Arm produced the Morello prototype board in 2022 to evaluate it on a real design. Arm's Memory Tagging Extension, introduced in the Armv8.5-A architecture, attaches a small tag to each memory granule and to each pointer and traps on a mismatch, catching a large fraction of buffer overflows and use-after-free errors at modest cost. Sixty years after Lisp machines checked type tags in hardware, tagged memory has returned for a different reason.
Conclusion
The clearest pattern in this succession is economic. Every major shift followed a change in the relative price of machine time and engineering time. FORTRAN could not have been accepted in 1957 on any terms other than matching hand-written code, because the machine was the expensive component and Backus knew it. Interpreted scripting languages could not have been accepted until the machine was nearly free. The choice of a language has always been a decision about where to spend cycles, and the arguments that appear to be about elegance are usually about that.
The second pattern is that nothing is ever replaced. Machine code, assembly language, Fortran, COBOL, Lisp, C, and every language described above are all in production somewhere today. The field accumulates rather than succeeds itself, because a language dies only when the last machine that runs it is scrapped, and backward compatibility in instruction sets keeps those machines alive far longer than anyone plans. An engineer entering electronics now will encounter more distinct languages in a career than an engineer of 1975 knew existed.
The third pattern is that hardware and languages shape each other in both directions, and the direction usually assumed is the less interesting one. ALGOL's recursion produced a commercial stack machine. Lisp's list structure produced tagged architectures and a workstation industry. COBOL's insistence on exact decimal arithmetic produced decimal instructions in the System/360 and, eventually, decimal formats in IEEE 754-2008. Fortran's aliasing rules were valuable enough that C changed its standard to recover them. The memory-safety argument is now producing capability hardware and memory tagging. Software follows hardware often enough that the reverse case is overlooked, and the reverse case includes some of the most interesting machines ever built.
What is settled and what remains open are both worth naming. Structured control flow, static type checking, separate compilation with explicit interfaces, and formally specified syntax are no longer argued about; they won, and every serious language now has them. What remains contested is what a program should check while it runs and what those checks should cost. That is the same question Backus's critics raised in 1954, when the currency was machine cycles rented by the month. The currency now is exploitable vulnerabilities and functional safety certification, and the answer is moving, slowly, toward paying more for the check.
For an electronics engineer in particular, the language is the last layer at which a design decision remains legible before it becomes machine behavior. The volatile qualifier, the Ada representation clause, the synthesizable subset of Verilog, and a MISRA rule forbidding an implicit conversion are all attempts at the same thing: making a language say precisely what the hardware will do, no more and no less. Seventy years of language history is largely the record of how difficult that has proved and how much of the difficulty was never about the machine at all.