It’s fascinating to trace the roots of a programming language’s core features, isn't it? When we talk about Go, one of the things that immediately springs to mind is its elegant approach to concurrency. But where did that come from? It turns out, it’s a story with a long and rich history, stretching back to the late 1970s.
Back then, multiprocessors were more of a research topic than a common reality. The big questions revolved around operating systems, interrupt handling, I/O, and how different processes could talk to each other. Ideas like semaphores, monitors, locks, and message passing were all floating around. Interestingly, researchers like Lauer and Needham showed that message passing and what we now call threads and locks were fundamentally equivalent – a pretty profound insight.
Then came a seminal paper by C.A.R. Hoare in 1978, introducing Communicating Sequential Processes, or CSP. This wasn't just another academic paper; it was a model programming language that fundamentally viewed input and output as the core elements of computing. The idea was simple yet powerful: parallel composition of communicating sequential processes. Communication is I/O, and parallel composition is multiprocessing. That was pretty much all you needed, according to Hoare, and it contained more groundbreaking ideas than many other papers combined.
CSP was mathematical, concise, and incredibly elegant. It generalized Dijkstra's guarded commands, using symbols like ! for sending and ? for receiving messages. For instance, p!value sends a value to process p, and p?var receives a value from p into the variable var. You could run commands sequentially ([A;B]) or in parallel ([A||B]). Repetition was handled with *[A], and guarded commands, which are like parallel if-then-else statements, looked like [a -> A [] b -> B]. The key takeaway here is that communication in CSP was synchronization, and each command could either succeed or fail. Crucially, there was no sharing of memory – a stark contrast to many contemporary approaches.
From CSP, distinct branches of language development emerged. One path led to Occam, a language developed by Inmos in the early 1980s to program their Transputer chip. Occam stayed very close to the core CSP concepts, with ports directly corresponding to hardware connections. Another significant branch gave us Erlang, developed at Ericsson in the late 1980s. Erlang embraced the functional aspects of CSP, introducing "mailboxes" and heavy reliance on pattern matching to unpack messages. Sending a message was directed to a process ID.
And then there’s the branch that eventually led to Go. This lineage includes languages like Newsqueak and Limbo, with a strong focus on channels as the primary mechanism for communication. Squeak*, a toy language from the mid-1980s, explored using concurrency to manage user interface input streams, demonstrating how processes could interact. Newsqueak, in 1989, aimed to make these concurrency ideas practical, syntactically resembling C but with an applicative and concurrent core. It introduced concepts like progs (similar to lambdas) and a select statement for handling communication, though its guards were limited to communication operations.
This historical journey highlights how Go’s concurrency model, with its emphasis on channels and goroutines, isn't a sudden invention but a carefully evolved concept, drawing inspiration from decades of research and practical experimentation in parallel and distributed computing. It’s a testament to the enduring power of ideas that, when refined and thoughtfully implemented, can shape the future of programming.
