Evaluation of Programming Languages Part 2A — Evolution of Major Programming Languages

Abde Manaaf Ghadiali
12 min readNov 19, 2023

--

First there was chaos, then there was assembly, and lo, the gods of programming said, ‘Let there be C.’ And from its divine lineage sprang the multitude of tongues, each boasting its own quirks and eccentricities, leaving developers to navigate a Tower of Babel in pursuit of the perfect code.

Contents

  1. Introduction
  2. Zuse’s Plankalkül
  3. Pseudocodes
  4. The IBM 704 and Fortran
  5. Functional Programming: Lisp
  6. The First Step Toward Sophistication: ALGOL 60 and Orthogonal Design: ALGOL 68
  7. Computerizing Business Records: COBOL
  8. The Beginnings of Timesharing: Basic
  9. Everything for Everybody: PL/I
  10. Two Early Dynamic Languages: APL and SNOBOL
  11. The Beginnings of Data Abstraction: SIMULA 67
  12. Summary

Disclaimer — The contents of this material delve into a comprehensive exploration of various programming languages and intricate language concepts. As these discussions may appear unfamiliar to some readers, it is important to note that detailed explanations of these topics will be provided in subsequent articles. Individuals who might find the current content challenging are advised to defer reading this article until they have acquainted themselves with the later sections of the book.

Introduction

This article aims to provide a comprehensive understanding of the evolution of various programming languages. It will delve into the historical contexts in which each language was created, emphasizing the unique features and goals that shaped their development. Through this exploration, readers will gain insights into the motivations behind the inception of these languages and their enduring influence in the realm of technology.

Genealogy of common high-level programming languages

Zuse’s Plankalkül

Zuse’s Plankalkül, developed in 1945 but not disclosed until 1972, remained unimplemented, yet influenced subsequent languages. It featured advanced data structures, including arrays and nested records. Despite the absence of a goto statement, it included an Ada-like iterative statement and a ‘Fin’ command for loop control. The language incorporated a selection statement without an ‘else’ clause. Notably, it introduced dynamic variable relationships in programs. Zuse’s manuscript showcased complex algorithms predating 1945, covering tasks such as array sorting, graph connectivity testing, mathematical operations (including square roots), and logic formula analysis with varying operator precedence. His extensive 49-page algorithm set for chess highlighted the language’s versatility and Zuse’s groundbreaking contributions to programming.

Pseudocodes

First, note that the word pseudocode is used here in a different sense than its contemporary meaning. We call the languages discussed in this section pseudocodes because that’s what they were named at the time they were developed and used (the late 1940s and early 1950s). However, they are clearly not pseudocodes in the contemporary sense.

In the late 1940s and early 1950s, the scarcity of user-friendly computers necessitated the development of higher-level languages known as pseudocodes. Contrary to its modern connotation, these pseudocodes were genuine programming languages used during that era. With the absence of high-level programming languages and supportive software, programmers relied on complex and error-prone machine code.

One such language, Short Code, operated through interpretation, offering a simplified programming experience at the cost of slower execution. Similarly, systems like Speedcoding extended machine languages to support floating-point operations, introducing the innovative feature of automatic address register incrementation.

A breakthrough arrived with UNIVAC’s A-0, A-1, and A-2 “compiling” systems between 1951 and 1953, which transformed pseudocode into machine code subprograms, streamlining programming while reducing source program lengths. Notably, these pseudocodes laid the groundwork for later high-level languages, distinct from the assembly languages of the time.

Note — Assembly Languages are quite different from the pseudocodes which evolved during the early 1950s.

The IBM 704 and Fortran

FORmula TRANslating System: FORTRAN

In 1954, the advent of the IBM 704 marked a significant leap in computing, ultimately paving the way for the development of Fortran. Prior to this, the absence of floating-point hardware restricted the speed of interpretive systems. The IBM 704’s hardware-based indexing and floating-point instructions brought an end to this limitation, particularly in the domain of scientific computation.

Fortran I, introduced shortly thereafter, included fundamental features such as input/output formatting, six-character variable names, user-defined subroutines, the ‘If’ selection statement, and the ‘Do’ loop statement. Notably, the language lacked explicit data-typing statements, with specific naming conventions implicitly determining variable types.

The subsequent release of Fortran II in 1958 resolved earlier complications, allowing independent compilation of subroutines, thus enabling easier program modifications. Despite the development of Fortran III, which saw limited distribution, it was the subsequent Fortran IV that garnered widespread usage, featuring enhancements such as explicit type declarations, a logical ‘If’ construct, and the ability to pass subprograms as parameters.

Fortran 77, established as the new standard in 1978, retained many of Fortran IV’s features while incorporating character string handling, logical loop control statements, and an ‘If’ statement with an optional ‘Else’ clause. Fortran 90 introduced dynamic arrays, records, pointers, and recursive subprogram calls, ushering in a significant shift from its predecessors.

With subsequent iterations like Fortran 95, which introduced the ‘Forall’ construct for easier parallelization, and Fortran 2003 and 2008, which added support for object-oriented programming, parameterized derived types, and co-arrays for parallel execution models, Fortran has continuously evolved to meet modern computational demands. Despite its early limitations, the language’s contributions revolutionized computing, acting as the pioneer in the realm of widely used high-level languages.

Functional Programming: Lisp

The emergence of Lisp, the first functional programming language, was a response to the growing demand for language features tailored for list processing, particularly in the realm of artificial intelligence (AI) applications. Initially conceptualized as a system for list processing, Lisp’s early version, referred to as “pure Lisp,” was designed as a purely functional language, primarily comprising atoms and lists as its fundamental data structures.

In contrast to imperative languages, Lisp’s computational processes rely on function application without the need for assignment statements or conventional variables. Recursive function calls facilitate repetitive processes, rendering the use of iterative loops unnecessary. This core principle of functional programming distinguished Lisp from its imperative counterparts, establishing it as a dominant force in AI applications for over twenty-five years.

While Lisp garnered a reputation for inefficiency, modern implementations have significantly improved its performance, with many contemporary versions being compiled for faster execution. Notably, two prominent Lisp dialects, Scheme and Common Lisp, have emerged to address specific programming needs. Scheme, known for its simplicity and usage of static scoping, excels in educational contexts and serves as an introduction to functional programming. On the other hand, Common Lisp balances the advantages of dynamic and static scoping, offering a comprehensive suite of data types, structures, and access control mechanisms.

Beyond Lisp, related languages such as ML, Miranda, Haskell, Caml, OCaml, and F# have evolved, each incorporating unique characteristics that expand the scope of functional programming. ML, while primarily functional, supports imperative programming and emphasizes compile-time determination of variable types. Miranda and Haskell embrace pure functional programming with the latter incorporating lazy evaluation, postponing expression evaluation until necessary. Caml and its object-oriented counterpart, OCaml, are descendants of ML and Haskell, featuring their own distinct features. Finally, F#, a .NET language inspired by OCaml, grants direct access to the comprehensive .NET library, enhancing its utility and versatility.

The First Step Toward Sophistication: ALGOL 60 and Orthogonal Design: ALGOL 68

ALGOL 60 emerged from a concerted effort to establish a comprehensive programming language tailored for scientific applications. Its name, an acronym for ALGOrithmic Language, underscored its purpose. Building upon the foundations of Fortran, ALGOL 60 not only expanded upon Fortran’s features but also introduced new constructs and concepts. Notably, it formalized the notion of data types, emphasizing a more flexible and powerful language design that was not tied to specific computing machines.

Notable advancements in ALGOL 60 included the formalization of compound statements, allowing for more complex programming structures. It also introduced the concept of block structure, enabling programmers to compartmentalize code segments for localized processing. Furthermore, ALGOL 60 facilitated the implementation of recursive procedures and stack-dynamic arrays, where array sizes were determined dynamically during execution.

The subsequent evolution, ALGOL 68, brought forth a wave of groundbreaking ideas in language design that continue to resonate within contemporary programming languages. A key hallmark of ALGOL 68 was its pursuit of orthogonality, exemplified by the incorporation of user-defined data types. This feature empowered users to fashion data abstractions tailored to specific problems, enhancing the language’s adaptability.

Additionally, ALGOL 68 introduced dynamic arrays, known as flex arrays, which allowed for the allocation of storage based on runtime requirements. This dynamic approach to arrays paved the way for more efficient and adaptable data management within programming environments.

While the ALGOL 58/ALGOL 60 initiative marked a significant milestone in the development of programming languages, it faced challenges that limited its widespread adoption. The language’s perceived complexity and its reliance on implementation-dependent input/output mechanisms hindered its acceptance within the programming community, particularly in the United States. Despite its groundbreaking contributions to computer science, including the creation of Backus-Naur Form (BNF), ALGOL 60 struggled to gain traction due to these practical hurdles.

Nevertheless, ALGOL 60 and its successor ALGOL 68 left an indelible mark on the history of programming languages, influencing subsequent language designs and inspiring a more nuanced approach to data types and program structure.

Computerizing Business Records: COBOL

COBOL, a foundational programming language utilized for nearly six decades, has had minimal influence on the design of subsequent languages, with PL/I being a notable exception. Its limited impact stems from the enduring adequacy of COBOL’s capabilities, specifically tailored to the domain of business applications. Marked as the “Common Business Language” (CBL), COBOL was envisioned to have user-friendly English-centric syntax, allowing both ease of use and comprehensibility for managerial oversight, while avoiding overly restrictive design constraints.

COBOL introduced innovative concepts, including the pioneering DEFINE verb for macros and hierarchical data structures, laying the groundwork for their incorporation into subsequent imperative languages. Despite its significance, the original COBOL faced criticism for lacking functions within its procedure division and restricting subprograms without parameters in versions predating the 1974 standard.

Mandated by the Department of Defense (DoD), COBOL’s survival hinged on the evolution of more efficient compilers and the advancement of computing technology. Over time, as compilers improved and computing systems became faster, cheaper, and equipped with larger memories, COBOL thrived, transforming the landscape of electronic accounting and leaving a lasting mark on business record-keeping practices.

The Beginnings of Timesharing: Basic

During the late 1970s and early 1980s, Basic (Beginner’s All-purpose Symbolic Instruction Code) gained immense popularity on microcomputers due to its user-friendly nature and adaptability to smaller memory systems. Its appeal lay in its accessibility for non-technical users and its straightforward implementation on limited-capacity computers. However, as microcomputers evolved and other languages emerged, Basic’s usage declined until the arrival of Visual Basic in the 1990s, sparking a resurgence of interest.

In 1963, the design of Basic was initiated with a specific focus on accommodating liberal arts students, employing terminals as the primary means of computer access. Its design goals emphasized user-friendliness, prioritizing ease of learning, pleasant interaction, swift turnaround for assignments, and unrestricted and private access.

The original Basic, while limited in functionality, represented a pioneering step as the first widely used language accessible through terminals connected to remote computers. Drawing from Fortran and ALGOL 60, Basic featured a minimalistic design with only 14 statement types and a sole floating-point data type. Surprisingly, Digital Equipment Corporation utilized an elaborate version of Basic, Basic-PLUS, to develop significant segments of their PDP-11 minicomputer operating system, RSTS, in the 1970s.

The resurgence of Basic in the 1990s was primarily catalyzed by Visual Basic’s capacity to streamline the development of graphical user interfaces (GUIs). As a result, Visual Basic gained widespread adoption, leading to the subsequent release of VB.NET with the introduction of .NET framework.

Everything for Everybody: PL/I

The advent of the IBM System/360 computer line necessitated the creation of a versatile programming language that could accommodate both scientific and business applications, as well as support systems programming and list processing. This led to the development of PL/I, initially known as Fortran VI, aimed at replacing Fortran, COBOL, Lisp, and assembly language applications. Despite its goal of maintaining compatibility with Fortran IV, PL/I rapidly evolved into a distinct entity, amalgamating the best elements of ALGOL 60, Fortran IV, and COBOL 60, along with a host of new constructs.

Notably, PL/I pioneered several significant features, including the ability to concurrently execute subprograms, handle 23 different types of exceptions, support recursive subprograms with optional disabling for non-recursive ones, and include pointers as a data type. Moreover, it facilitated the referencing of cross-sections of arrays, enabling efficient data manipulation.

However, the language’s comprehensive approach, aiming to include any implementable useful construct, resulted in a complex and unwieldy system, lacking in cohesive design and user-friendliness. Despite its innovative features, PL/I suffered from several inadequately designed constructs, such as pointers, exception handling, and concurrency, which, while groundbreaking, posed challenges for programmers unfamiliar with such a diverse and intricate set of functionalities.

Two Early Dynamic Languages: APL and SNOBOL

APL and SNOBOL, while differing significantly in appearance and purpose, share key characteristics that define their dynamic nature. Both languages embrace dynamic typing and dynamic storage allocation, wherein variables remain essentially untyped until assigned a value. This assignment, in turn, dictates the variable’s type, and storage allocation occurs only at the point of value assignment due to the inherent uncertainty of required storage beforehand.

APL distinguishes itself with an extensive set of potent operators, represented by a plethora of symbols. This abundance, while empowering for developers, posed challenges for implementors. A key feature contributing to this profusion is APL’s support for a wide range of unit operations on arrays. For instance, the transpose of any matrix is achieved through a singular operator. Despite the language’s remarkable expressivity, the multitude of operators can make APL programs intricate and challenging to decipher.

Contrary to APL, SNOBOL was meticulously crafted with a specific focus on text processing. The core strength of SNOBOL lies in its robust operations for string pattern matching, making it particularly adept at handling textual data. Initially employed in applications like text editors, SNOBOL’s dynamic nature, while advantageous for certain tasks, resulted in comparatively slower performance when compared to alternative languages. Consequently, SNOBOL is no longer the preferred choice for such applications.

In examining APL and SNOBOL, we find two early dynamic languages with distinct strengths and purposes. APL’s abundance of operators facilitates powerful array operations but introduces complexity in program readability. Meanwhile, SNOBOL’s specialization in text processing, while initially advantageous, led to diminished usage in favor of more performance-oriented alternatives.

The Beginnings of Data Abstraction: SIMULA 67

The origins of data abstraction can be traced back to the development of SIMULA 67, an extension of ALGOL 60 designed explicitly for system simulation. The initial implementation of its predecessor, SIMULA I, took place in late 1964 on a UNIVAC 1107 computer. SIMULA 67 inherited key features from ALGOL 60, including block structure and control statements.

The pivotal drawback of ALGOL 60 and other contemporary languages for simulation applications lay in the design of subprograms. Simulation demands subprograms capable of resuming execution from where they previously halted. Subprograms possessing this characteristic are termed coroutines, establishing a more egalitarian relationship between the caller and called subprograms, as opposed to the conventional master/slave dynamic prevalent in most imperative languages.

To address the need for coroutines in SIMULA 67, the class construct was introduced. This development marked a significant milestone, as it laid the groundwork for the concept of data abstraction. Data abstraction, an integral aspect of SIMULA 67, would later become the cornerstone of object-oriented programming (OOP). The introduction of classes in SIMULA 67 not only facilitated the creation of coroutines but also pioneered a new paradigm in programming that prioritized encapsulation and abstraction, setting the stage for the evolution of modern OOP languages.

SIMULA 67’s innovation in introducing the class construct to support coroutines marked a crucial step in the evolution of programming languages. This development laid the foundation for data abstraction, a concept that would later blossom into the fundamental principle of object-oriented programming.

Summary

In conclusion, the journey through the evolution of major programming languages presented in this article unveils a rich tapestry of innovation, challenges, and pivotal moments that have shaped the landscape of computer science. From the foundational concepts of Zuse’s Plankalkül and the development of pseudocodes to the advent of Fortran, Lisp, and the sophistication introduced by ALGOL 60 and ALGOL 68, each language reflects the dynamic interplay of technological advancements and programming needs.

The exploration extends to languages designed for specific domains, such as COBOL for business applications, Basic for early microcomputers, and PL/I for the versatile IBM System/360. The discussion of APL and SNOBOL highlights the diversity of dynamic languages, each tailored to unique tasks. SIMULA 67’s pivotal role in introducing data abstraction and laying the foundation for object-oriented programming marks a significant turning point in language design.

As we reflect on this historical journey, it becomes evident that the evolution of programming languages is a dynamic and ongoing process, shaped by the ever-changing needs of the computing world. Each language discussed in this exploration has left an indelible mark, contributing to the rich mosaic of tools and paradigms that programmers utilize today. This comprehensive survey serves not only as a historical account but also as a source of inspiration for future advancements in programming language design.

Get ready for our next article! We’ll dive into the world of Some Early Descendants of the ALGOLs, explore Logic Programming with Prolog, uncover the story behind Ada’s monumental design effort, and navigate through the histories of Smalltalk, C++, Java, and more.

--

--

Abde Manaaf Ghadiali

ML Engineer and Python Backend Developer, Currently Pursuing Master's Degree at The George Washington University