|
That room. The tape drives in their cabinets along the far wall, the operator's console in the centre, the line printer to the right. It looks like something from Kubrick: the same antiseptic geometry, the same monolithic seriousness, the same implication that whatever happens here is important enough to require its own architecture. This is a Philips P1100. In 1973, I was twelve years old, and this is where I started programming. I got the opportunity through school. The P1100 was a Dutch mainframe, not widely known outside Northern Europe, and the fact that a twelve-year-old was permitted to approach it probably says more about 1970s Scandinavian attitudes to children than about any pedagogical intention. But approach it I did. COBOL and FORTRAN, mostly. Punch cards. Line printers. Typewriter console input. Thirty-six-bit words and 32K words of core memory – actual magnetic cores, the kind you could theoretically see with a magnifying glass. Spinning tape stations and disk units. The whole physical apparatus of computation as it existed before anyone thought to make it personal. What the photographs convey, and what no description quite captures, is the physicality of early computing. These were rooms, not screens. You walked into the machine. The tape drives were furniture. The noise was constant. Programming in that environment carried a particular weight; there was nothing casual about it, nothing disposable, nothing you could do from bed with a laptop. The seriousness was built into the space. I don't mention this for nostalgia. I mention it because something from that period has stayed with me through fifty years of subsequent work, and I think it matters for understanding why I build the way I build. A Language That Trusts You Six years after the P1100, in 1979, I encountered Lisp. I was eighteen, and the encounter came through the legendary August 1979 issue of BYTE magazine, devoted entirely to Lisp. I've written about this before, so I won't repeat the full story here; but the experience deserves its place in this genealogy because it changed the direction of everything that followed. I should say what computing felt like in the late 1970s, for anyone who wasn't there. The dominant paradigm was procedural: FORTRAN, COBOL, Pascal, various assembly languages depending on your hardware. Programming meant telling the machine what to do, step by step, in a language designed for the machine's convenience as much as the programmer's. The programmer was an operator. The metaphor was industrial. I had spent six years in that world. It was what programming was. Lisp was different in kind, not just in degree. What I encountered was a language that didn't tell me what to do. It waited. It provided a set of primitives so minimal they seemed almost absurd; seven or eight special forms, a way to define functions, a way to combine them, and the extraordinary implication that this was sufficient for anything I could imagine. The language was smaller than what I'd been using, and it could do more. That paradox has never stopped being interesting to me. What Lisp offered, and what I wouldn't have the vocabulary to articulate until years later, was freedom. Not freedom as a marketing term or a political slogan, but freedom as an engineering condition: the ability to reshape the language to the problem rather than reshaping the problem to fit the language. In Lisp, the programmer was not an operator. The programmer was a maker of tools, a builder of languages, a creative agent trusted with the full power of the system. The culture around Lisp carried this same ethos. The people who shaped it (Steele, Gabriel, Kiczales, Norvig, among others) were not priests. They were builders, hackers, improvisers. They valued expressiveness, wit, elegance in the mathematical sense, and above all, the conviction that the person at the keyboard was intelligent enough to be trusted with dangerous tools. The community was irreverent, argumentative, often brilliant, and entirely uninterested in policing anyone's tone or orthodoxy. You were judged by what you built, not by which catechism you recited. I mention these names because they are not abstractions to me. I was eighteen. I was reading their papers. I was trying to implement what they described. Immediately after that BYTE issue, I implemented a Lisp in 6502 assembler, using an assembler I had written in BASIC. I tell you this not to impress but to convey the intensity of the response. When something is that good, you build it yourself to understand it. CLOS and the Workshop TraditionThe progression from basic Lisp to the Common Lisp Object System (CLOS) in the mid-1980s was not, for me, a move from one paradigm to another. It was an expansion within the same tradition. CLOS is difficult to explain to anyone whose experience of object-oriented programming was formed by Java, C++, or Python. In fact, some of us maintained even then that CLOS was not object-oriented at all; the name was a concession to the terminology of the period, not a description of what it actually was. Those languages treat objects as containers: data and methods bundled together, accessed through interfaces, extended through inheritance. The programmer works within the object. CLOS transcends this entirely. Methods don't belong to objects; they belong to generic functions. Dispatch can happen on any combination of argument types. Method combinations (:before, :after, :around) let you layer behaviour without modifying existing code. The Metaobject Protocol (MOP) lets you redefine how the object system itself works. The result is a system of extraordinary power and openness. You could override anything. You could extend anything. You could reshape the behaviour of the system at any level, including the level at which behaviour is dispatched. CLOS treated the programmer not as a user of the object system but as its co-author. The system was a workshop, not a cathedral, and the door was always unlocked. This mattered to me practically, not just aesthetically. When I built HotLisp for the Royal College of Music in Stockholm (a Common Lisp implementation written in C that treated MIDI events as first-class citizens), I was already integrating music directly into the computational core. When I later built Igor Engraver, CLOS became the substrate on which the entire semantic model rested. The ability to extend, compose, and reshape; to add new types of musical objects that participated seamlessly in existing operations; to layer specialised behaviour onto generic frameworks without breaking them: these weren't theoretical luxuries. They were the reason the software worked. I taught algorithmic composition using Lisp at the Royal College. My students, who were composers, not computer scientists, understood the freedom immediately. You could express musical ideas directly, without the mediation of a language designed for someone else's problems. The gap between thinking and making was as small as I have ever seen it in any medium. Having Been ThereI am, as of this writing, sixty-four years old. I have been programming for over fifty years. I say this not as credential but as context, because having been there changes what you see. I was there for the AI winter. I watched a field that had promised the moon retreat into a decade of funding cuts and reputational collapse, dragging Lisp's standing down with it. The language didn't deserve the association; it was punished for the sins of researchers who had over-promised. I kept using it anyway, because the language hadn't changed, only its fashionability. This was the first time I learned that technical merit and cultural standing are largely unrelated. I was there for the object-oriented conquest of the 1990s. I watched as C++ and then Java established OOP as orthodoxy, complete with design pattern catechisms and UML diagrams that looked more like religious iconography than engineering documentation. CLOS, which had solved the problems these languages were struggling with years earlier, was invisible because it ran on the wrong platform and belonged to the wrong tribe. The industry chose what was marketable over what was good. This was the second time I learned that lesson. I was there for the web's arrival, which changed everything about deployment and nothing about the fundamental problems of building complex software. I was there for the enterprise Java years, when 'architecture' meant XML configuration files and dependency injection frameworks and a peculiar conviction that more abstraction was always better, regardless of what it cost in comprehensibility. I was there for the functional programming renaissance, which rediscovered principles that Lisp had embodied since the 1950s, often without acknowledgement and frequently with a missionary zeal that replicated the very dogmatism it claimed to reject. I am here for the current AI explosion, which rhymes with the original AI boom in ways that make my skin prickle. I have seen this arc before: extraordinary technical promise, sweeping claims about imminent transformation, and a market that moves faster than the underlying science. Time will separate what is durable from what is fashionable. None of this is complaint. It is observation. When you have been programming for fifty years, you develop a particular relationship with trends: you have seen enough of them arrive, dominate, and recede to know that the arrival tells you very little about the value and the dominance tells you nothing about the longevity. What remains after the trend passes is what was true about it. Immutability was true about functional programming. The JVM was true about Java. Interactive development was true about Lisp all along. The thing that has remained true for me, through every cycle, is the freedom principle. The conviction that the programmer should be trusted, that the tools should serve the maker rather than constrain them, that the ability to reshape your instruments is not a luxury but a precondition for doing serious work. I did not learn this from a manifesto. I learned it from a mainframe in 1973 and a Lisp prompt in 1979, and everything since has confirmed it. What Was Lost Igor Engraver was the fullest expression of this principle I had achieved. Twelve people, $7.5 million in investment (2024 equivalent), a music notation system built entirely in Common Lisp that introduced semantic modelling to the field. Conductors were interested. Composers were interested. The architecture was sound. The project ended in 2002 after a combination of venture capital pressure, management-imposed feature creep, and the collapse of M&A activity following September 11, 2001. The technical architecture was sound; the business environment was not. I won't rehearse the full history here; it's documented elsewhere. What matters for this essay is what was lost and what survived. What was lost was the software, the team, and the years of accumulated work. What survived was the knowledge: of what works in music notation architecture, of what CLOS makes possible, of what fails when business logic overrides engineering discipline. And what survived, underneath all of it, was the conviction that the freedom principle was correct and that the work deserved to be done properly. Most people, having had a project of that scale taken from them, do not try again. I understand why. The rational calculus says the risk exceeds the reward. But the rational calculus doesn't account for the fact that you still know how to do it, that you've learned what you didn't know the first time, and that nobody else is going to build this. The ReturnWhen I came to Clojure, I came home. I don't mean this sentimentally. I mean it technically. Clojure is a Lisp; it thinks in the same shapes, provides the same minimal-but-sufficient primitive set, and trusts the programmer with the same radical freedom. But it adds things that Common Lisp never had and that my work desperately needed: immutable data structures by default, Software Transactional Memory for concurrent coordination, and the entire JVM ecosystem for deployment, GUI development, and cross-platform reliability. I've written extensively about these on the blog, so I won't rehearse the technical details here. What matters for this essay is the genealogical thread. I've called this 'Clojure for closure', and the wordplay is deliberate. It is a return to a native language after decades away, carrying everything those decades taught me. The CLOS patterns came with me. Ooloi uses Clojure's multimethods with the Methodical library to achieve CLOS-like method combinations: :before, :after, :around modifiers that layer behaviour exactly as they did in Common Lisp. The hierarchical type system uses Clojure's `derive` mechanism to create inheritance-like relationships without classes, mirroring CLOS's approach to multiple inheritance through composition rather than rigid hierarchy. Generic functions dispatch on argument types just as they did in CLOS, with operations defined outside the data they manipulate. Rich Hickey, Clojure's creator, made choices that resonate specifically with the tradition I come from. 'Mutability in bounded contexts is fine'. 'Solve problems first'. The emphasis on what you can build, not on what catechism you recite. Clojure didn't inherit the Lisp purity culture that never really existed in the first place; it inherited the Lisp builder culture, the one that judged you by what you shipped rather than which monads you could name. But Clojure also gave me something new. Immutability as a default changes how you think about time, state, and coordination. In Common Lisp, you could write immutable code, but the language didn't push you toward it. In Clojure, immutability is the grain of the wood. This inversion turned out to be profound for music notation specifically, because a musical score is a temporal structure where the meaning of any element depends on everything that precedes it. The semantic engine that results from this is something Igor Engraver, for all its strengths, could never have achieved. Where the Genealogy ArrivesOoloi's plugin system is, in a specific sense, the culmination of everything this essay describes.
The core engine is written in Clojure and architecturally closed. I've written about this elsewhere as the 'monastic core' principle. The freedom is at the perimeter: any JVM language can write plugins, and the plugin API speaks each language's idioms natively. A Java developer writes Java. A Kotlin developer writes Kotlin. Nobody is forced to learn Clojure or to understand the internals. The benefits of the architecture propagate without requiring conversion. This is the CLOS principle, expressed architecturally. The system trusts the developer. The developer works in their own language, with their own patterns, and the underlying architecture handles the coordination. The monastery uses Latin internally because Latin is precise; but when teaching farmers improved agriculture, you speak their language. This is not compromise. It is proper boundary design, and it is the lesson of fifty years in the workshop tradition. When I sit at this keyboard today, fixing a macOS menu bug or stripping debug symbols from a jlink runtime, I am using skills accumulated across the full span of what I've described. The mainframe taught me that serious work requires serious infrastructure. Lisp taught me that freedom is an engineering condition, not a slogan. CLOS taught me that the system should trust the programmer. The loss of Igor Engraver taught me that good architecture survives the business that funded it, if someone is stubborn enough to rebuild. Clojure taught me that immutability changes what's possible. The whole genealogy is present in every design decision, whether or not it's visible. I don't know if Ooloi will succeed, whatever that is. I know the architecture is right. I know the foundations carry what needs to be built on top of them. And I know where the freedom comes from, which is what I wanted to write down.
2 Comments
I'm one of the world's most committed anti-religious people. Despite decades at organ consoles in churches and cathedrals, I stand with Hitchens: religion is humanity's adolescent phase, something we need to outgrow. Its influence is fundamentally harmful. But when I read something like How Lisp Became God's Own Programming Language, I completely understand the reverence the author describes. There's something about Lisp – and Clojure – that creates what you can only call a transcendental response. Nothing actually transcendental happens, of course, but the feeling is real. What Lisp gives you is freedom. I've written about 'windsurfing through parentheses' before, and the metaphor sticks because it captures something essential. Most programmers are chained to the oars of enterprise slave galleys, with CTOs yelling 'RAMMING SPEED!' like that brilliant scene from Ben-Hur. Meanwhile, those of us who've found Lisp are windsurfing in circles around them, enjoying a freedom they can barely imagine. The discovery feels like Dave Bowman meeting the monolith: 'My God... it's full of stars!' That vertigo when you realise this thing's inner dimensions vastly exceed its outer ones. Lisp isn't transcendental, but it works like a star gate in both senses. The language doesn't get in your way, and it opens new ways of thinking. At the same time, it's so simple that complexity becomes manageable.
I remember that August 1979 BYTE magazine perfectly. The cover promised mysteries, the articles delivered. I couldn't wait to start implementing what they described – eventually doing it in 6502 assembler, using an assembler I'd written in BASIC. Everything clicked, even as a teenager. This was real freedom, expressed as code. Years later, I wrote HotLisp (or 'HotLips' – M.A.S.H. was huge then) for the Royal College of Music in Stockholm. It was incredibly ambitious: a full Common Lisp that treated MIDI events as first-class citizens. Looking back, I see this as the beginning of what became Igor Engraver – integrating music directly into the computational core. We used it to control our Synclavier and MIDI synths whilst teaching algorithmic composition to advanced students at the Royal Academy. The Two-Bit History article nails something important about Lisp's mystique. It traces the evolution from McCarthy's 'elegant mathematical system' through AI research, Lisp machines, and SICP's role in making it the language that 'teaches you programming's hidden secrets'. Each phase built the reputation. What the article doesn't cover is the educational betrayal that followed. Computer science departments got it right for a while – they taught Scheme as a first language because it let students focus on learning algorithms rather than wrestling with syntax. Pure freedom to think about problems. Then Java Enterprise was foisted upon the world, the departments caved in, and they started churning out galley slaves instead of computer scientists. I see this as nothing short of high treason. But here's what really matters: that freedom has evolved in Clojure. Rich Hickey didn't just bring Lisp to the JVM – he solved problems that even Common Lisp couldn't handle elegantly. Those immutable data structures aren't academic toys; they're game changers that eliminate whole categories of bugs whilst making concurrency and parallelism natural instead of terrifying. The effects ripple out: undo/redo becomes trivial, and the JVM gives genuine multi-platform reach. This isn't just improvement – it's architectural breakthrough disguised as evolution. Clojure keeps Lisp's essential quality (that feeling of discovering how programming should work) whilst solving modern problems McCarthy couldn't have anticipated. The poor souls in corporate Java shops keep rowing, occasionally granted small mercies as functional concepts trickle in – hints of the freedom they're missing. I wish they could experience what we know: programming doesn't have to feel like industrial labour. There's a way of working where ideas flow directly into code, where the language becomes transparent, where you stop fighting tools and start windsurfing through solutions. Maybe that's the point. As McCarthy noted in 1980, Lisp survives not because programmers grudgingly accept it as the best tool for each job, but because it hits 'some kind of local optimum in programming language space'. It endures even though most programmers never touch it, sustained by reports from those who've experienced its particular form of computational enlightenment. Until we can imagine God creating the world with some newer language – and I doubt that day is coming soon – Lisp isn't going anywhere. Read the full article at Two-Bit History: https://twobithistory.org/2018/10/14/lisp.html After a year building the backend of Ooloi with Claude, I’ve learned this:
Successful AI collaboration isn’t about creative freedom. It’s about harsh constraint. AI will overstep. Your job is to correct it—immediately, uncompromisingly. The friction isn’t failure. It’s the method. Read the full piece – which I asked the AI to write in its own voice – here. Claude & Clojure It's no secret that I use Generative AI, specifically Claude Sonnet, to assist with the Ooloi project. I use it for writing Clojure tests TDD fashion, for generating Clojure code, for generating documentation, READMEs, architectural design documents and much more. Above all, I use Claude for exploring architectural strategies before coding even begins. It's somewhat reminiscent of pair programming in that sense: I'd never just task GenAI with generating anything I wouldn't scrutinise very carefully. This approach works very well and allows me to quickly pick up on good design patterns and best practices for Clojure. Claude & Python Overall, working with Claude on Clojure code works surprisingly well. However, this is not the case when I try to involve Claude for coding in Python, the main language I use as an AWS Solutions Architect. Generative AI struggles with creating meaningful Python tests and code – especially tests, which rarely work at all. This hampers its use as an architectural discussion partner and a TDD assistant. In fact, I've given up trying to use Generative AI for coding in Python. DifferencesI have a deep background in Common Lisp and CLOS, dating back to the 1970s. I've written Common Lisp compilers and interpreters, as many Lispers did in those days. The standard practice was to write a small kernel in assembler or C or some other low-level language, and then use it to write an optimising compiler on top of it to replace the kernel in an iterative fashion, sometimes using transformations of source code based on lambda calculus. (I still remember that paper by Guy Steele.) I see Common Lisp essentially as a big bag of good-to-haves (a really excellent one, mind you). As such, it was designed by committees over a period of decades. Clojure, on the other hand, is much tighter and rests solidly on consistently applied computer science design principles. Common Lisp is pragmatic and eclectic and thus somewhat sprawling in design. Clojure, in comparison, is smaller and much more focussed, even opinionated in nature, and for clear reasons. People attracted to Common Lisp and Clojure tend to be pretty well versed in computer science, especially Clojurians who generally have a good understanding of functional programming and immutable data structure concepts. Thus, the public code "out there" on sites like GitHub tends to be fairly advanced and of high quality. Python is an entirely different ballgame. It's one of the most commonly used languages today, and the public code base is absolutely enormous. This also means that the quality of that public code varies considerably. Also, Python is not functional at heart, and its data structures aren't immutable: side effects is the name of the game. Python programmers, though much greater in number than Clojure programmers, range from script kids to computer scientists. Thus, public Python code is much more all over the place and of varying quality. This may make it harder for a large language model to reason about. I wondered whether these differences accounted for the discrepancies in the usefulness of Claude and other LLMs as coding assistants in Clojure and Python. Asking ClaudeSo I decided to ask Claude 3.7 itself. I shared the Clojure codebase with it and asked why it thought results were so much better for Clojure than for Python. This is what it said:
It then continued, quoting the code base:
I guess this answers my question about Clojure vs Python. It's not just the functional and immutable aspects of Clojure, it's also specifying the domain stringently through design, architectural discussons, specs, and tests. The Ooloi project in particularWith all that out of the way, I then went on to describe how I use Claude as a discussion partner before code is generated, and the TDD approach I'm using where the tests of course describe the domain. Claude was almost embarrassingly enthusiastic:
I continued: "I also use Claude to create ADRs, READMEs, introductions for newcomers, Dev plans, etc. I'm quite open about this; transparency is paramount in an open-source project, and the idea is to facilitate collaborators' understanding of the Ooloi project as much as possible. This means that adherence to best practices, the use of sane architecture, abstracting away the complex stuff without compromising on performance or flexibility, etc, all are central." Claude responded:
We then went on discussing open-source strategies, tutorials and onboarding materials for contributors and much more which I'll spare you from for now. Finally, I asked it to summarise its views on Ooloi as a project:
Now, this level of enthusiasm and praise from an anthropomorphic-presenting LLM (essentially a glorified Markov chain) always makes me deeply suspicious – I'm absolutely allergic to toxic positivity, especially the kind from the USA – so I asked it "Are you sure you're not overly enthusiastic just to please me?". It replied:
I then asked Claude 3.7 to comment on my journey from Common Lisp to Clojure and on the influence from Common Lisp and CLOS on Ooloi:
And finally, I just couldn't resist asking: "What would Rich Hickey say?"
I guess that hypothetical assessment is good enough for me at this point. Still not quite sure that Claude isn't giving me a friendly reach-around, though... ;)
When I started programming in Lisp in 1979, after reading an article in BYTE Magazine, I hardly imagined that 45 years later I'd be embarking on a new Lisp adventure. Yet here we are, with FrankenScore (to be renamed Ooloi upon open-source release) – a modern music notation software built with Clojure. It's a project that brings together all my lifelong passions: music, programming, and the pursuit of elegant solutions to complex problems. The Path from Common Lisp to Clojure My journey with Lisp began in an era when optimising Common Lisp compilers were cutting-edge technology. I cut my teeth implementing Common Lisp interpreters and compilers (as one did in those days), delving into the intricacies of a truly original programming language. This experience shaped my understanding of what a powerful, flexible programming language could be. And now in 2024 I find myself in the world of Clojure, a modern Lisp dialect that runs on the Java Virtual Machine. The transition feels both familiar and novel. Clojure's emphasis on immutability and its handling of concurrency through Software Transactional Memory (STM) aligns with the functional programming principles I've long appreciated in Lisp. But it's not just about the language. The ecosystem around Clojure – the JVM, the interoperability with Java libraries, the rich set of tools and frameworks – provides a robust foundation that we could only dream of back in the Common Lisp days. CLOS Thinking in a Clojure World One of the more interesting aspects of this transition has been adapting CLOS-style thinking to Clojure's more data-centric approach. CLOS, with its powerful multiple inheritance and method combination features, encouraged a certain way of modelling problems. In FrankenScore, I've found myself reaching for these familiar patterns, but implementing them in Clojure's more functional style. For instance, the use of Clojure's protocols and multimethods, combined with hierarchies and the Methodical library, allows us to achieve CLOS-like polymorphism. It's a different approach, but one that feels natural once you embrace Clojure's philosophy. Clojure's deliberate avoidance of traditional object-oriented features felt immediately familiar and refreshing. It resonates with CLOS's approach, which many, including myself, have long regarded as transcending traditional OOP. Composition over inheritance, a principle I always valued even in the CLOS days, is not just a best practice in Clojure but the very fabric of its design philosophy. This alignment between CLOS's advanced features and Clojure's functional paradigm makes the transition feel natural and even inevitable. Changes in ThinkingPerhaps the most significant shift has been in embracing Clojure's emphasis on immutable data structures and pure functions. While these concepts weren't foreign in Common Lisp, they're central to Clojure's design. This shift encourages a style of programming that's inherently more thread-safe and easier to reason about – crucial for a complex application like FrankenScore. Another major change has been adapting to Clojure's more minimalist standard library compared to Common Lisp. This has led to a greater appreciation for carefully chosen, interoperable libraries and a more modular design approach. SimilaritiesDespite the differences, there are of course similarities in the overall approach. The emphasis on interactive development, the power of macros for domain-specific languages and the elimination of boilerplate code, plus the satisfaction of working in a dynamic, expressive language – these are all as present in my Clojure work as they were in my Common Lisp days. Moreover, the focus on solving complex problems through abstraction and composition remains. Whether it's CLOS or Clojure, the goal is still to create systems that are powerful, flexible, and pleasant to work with. Closing ThoughtsThis journey from Common Lisp to Clojure, from Igor Engraver to FrankenScore/Ooloi, is both challenging and rewarding. It's a testament to the enduring power of Lisp's ideas and the continued evolution of programming languages.
As I continue to develop FrankenScore, I'm captivated by the possibilities that Clojure and its ecosystem offer. While creating a powerful music notation software is the immediate goal, the project's scope extends far beyond that. It's an exploration of the synergies between music, technology, and open-source collaboration – a playground where these elements intersect and interact in novel ways. To those considering a similar journey, I'd say: embrace the change, but don't forget the lessons of the past. The parentheses may look familiar, but the world inside them is ever-evolving. |
AuthorPeter Bengtson – SearchArchives
February 2026
Categories
All
|
|
|
Ooloi is an open-source desktop music notation system for musicians who need stable, precise engraving and the freedom to notate complex music without workarounds. Scores and parts are handled consistently, remain responsive at scale, and support collaborative work without semantic compromise. They are not tied to proprietary formats or licensing.
Ooloi is currently under development. No release date has been announced.
|





RSS Feed