The Hidden Gem in S/SL: Why Dataless Languages Matter
2025-11-08
I’ve written a fair number of languages, compilers, interpreters, operating systems, and embedded code over my career. Certain themes keep recurring—like symptoms of a chronic disease that won’t go away. S/SL. UNIX pipelines. Failure Driven Development. Multiple notations for different concerns. Massive parallelism. First principles thinking.
I’ve written about many of these, but least of all S/SL. That’s a gap worth filling, because S/SL contains an idea that cuts across everything else I think about: how to enforce architectural discipline through language design.
In this article, I want to discuss my main inspiration from S/SL—a 1970s compiler construction language that most programmers have never heard of, but which demonstrates something fundamental about separating architectural thinking from implementation details.
What is S/SL?
S/SL stands for Syntax/Semantic Language. It was designed for writing compilers—specifically the parts that parse input, analyze semantics, and generate code.
Here’s what makes it unusual: S/SL has no data definitions. You can’t declare integers, strings, arrays, or records. You can only declare that data exists and give it a name—a handle.
When you write S/SL code, you declare operations like this:
mechanism Int:
...
oAddIntegers
...
This says “an integer addition operation exists.” It doesn’t say what integers are, how they’re represented, or how addition works. Those details live elsewhere, in what S/SL calls the “host language”—typically C or Pascal.
S/SL code orchestrates operations. The host language implements them. The two layers are completely separate.
The Hidden Gem
The genius isn’t the parsing—it’s the enforced separation between architecture and implementation.
S/SL makes it impossible to mix concerns. You literally cannot specify data layout in S/SL because the language has no syntax for it. You cannot optimize algorithms in S/SL because you can’t see the data structures. You must think architecturally—what operations happen in what order—and push implementation details down to the host language.
This seems like a limitation. It’s actually a discipline.
Most programming languages let you do everything in one place. You can design the architecture, specify the data structures, implement the algorithms, and optimize the performance all in the same file, using the same syntax. This seems convenient. It’s actually how architectural clarity dies.
When everything lives in the same language, the temptations are constant. You’re sketching high-level flow and notice an inefficient data structure—might as well fix it now. You’re designing component interactions and spot an optimization opportunity—just a quick inline, no big deal. Each decision seems reasonable in isolation.
But architectural thinking requires a different mental mode than implementation thinking. Architecture asks: what’s the right structure? Implementation asks: what’s the fastest way to execute this structure? When you can jump between these modes freely—in the same file, same syntax, same mental context—you do. The layers blur. You break your flow — your train of thought. Design intent gets buried under a mixture of structural decisions and performance tweaks, and six months later nobody can tell which is which.
S/SL prevents this by making it impossible. Architecture lives in S/SL. Implementation lives in the host language. They connect through declared operations—handles that specify what exists without specifying how it works.
Why Split Design This Way?
I learned this principle before I ever wrote a compiler. In the Core Physics program at university, we were taught to create custom notations for isolating aspects of complicated problems. Physicists joke about “spherical cows”—deliberately oversimplified models that let you focus on one phenomenon while ignoring everything else. A spherical cow in a vacuum isn’t realistic, but it lets you understand gravitational motion without tangling it with aerodynamics, leg mechanics, and digestion.
(I’ve written more about this in The Spherical Cows of Programming, if you’re interested in the broader pattern.)
S/SL is a spherical cow for control flow architecture. It strips away data structures, optimization concerns, and implementation details, leaving only the architectural skeleton visible. This isn’t a limitation—it’s the point. You can’t think clearly about architecture when you’re simultaneously thinking about memory layout.
The separation matters because designing structure and implementing mechanics require fundamentally different approaches. When you’re figuring out how components should connect, you need to see the big picture. When you’re optimizing an algorithm, you need to focus on the details. Trying to do both simultaneously—in the same file, with the same syntax—means constantly context-switching between incompatible mental modes.
S/SL’s dataless approach makes the split enforceable rather than aspirational. The S/SL layer sees only handles and operations. The host language layer sees only the implementation of those operations. Neither layer can reach into the other’s concerns.
This has practical benefits:
You can understand each layer independently. The S/SL code shows you the architectural flow without implementation noise. The host language code shows you the implementation details without architectural complexity.
You can change each layer independently. Need a different architecture? Rewrite the S/SL without touching the host language. Need a different data structure? Change the host language without touching the S/SL.
You can optimize at the right level. Architectural optimization means simplifying the flow, reducing the number of operations, restructuring components. Implementation optimization means better algorithms, better data structures, better use of hardware. These are different activities. S/SL lets you do each without the other getting in the way.
Beyond Sequential Control Flow
S/SL demonstrates that you can enforce architectural discipline through language design. Make mixing concerns impossible by giving different concerns different languages.
But S/SL inherits an assumption from its era: programs execute sequentially, one operation after another. This matches most programming languages, but it’s not how all problems work.
Consider electronic circuits. Components run concurrently, each responding to inputs whenever those inputs change. A circuit diagram shows multiple signal paths, feedback loops, components with multiple input and output pins. The notation matches the problem—inherently concurrent systems described with concurrent notation.
UNIX pipelines hint at concurrent thinking. S/SL uses UNIX pipelines to decouple compiler phases—scanning feeds parsing feeds semantic analysis feeds code generation. Each phase runs as a separate process. But within each phase, S/SL returns to sequential control flow.
What if we applied S/SL’s architectural discipline without the sequential constraint? This is what I’ve been exploring in PBP—Parts-Based Programming, a diagrammatic programming language where components have multiple input ports and multiple output ports, run concurrently, and communicate through message passing.
The architectural clarity S/SL provides through datalessness, PBP provides through visual isolation. Each component is a box with explicit ports. Connections are explicit arrows. No hidden control flow. No shared state. No sequential assumption forcing inherently concurrent relationships into before-and-after chains.
S/SL got the separation right: architecture in one notation, implementation in another. The next step is maintaining that separation while embracing concurrency as a natural model—not because all problems are concurrent, but because concurrent notation makes certain architectural relationships visible that sequential notation obscures.
The lesson isn’t “use S/SL” or even “use dataless languages.” The lesson is: use deliberately constrained notations to enforce architectural thinking. S/SL constrained data to force architectural clarity. We can apply the same principle with different constraints, producing notations suited to different kinds of problems—including problems where concurrency is fundamental rather than bolted on as an afterthought.
That’s the hidden gem in S/SL: not the specific technique, but the demonstration that language constraints can enforce the discipline we need to think clearly about architecture.
References
S/SL was developed by James Cordy, Ric Holt, and David Wortman at the University of Toronto in 1980. The original paper “An Introduction to S/SL: Syntax/Semantic Language” appeared in ACM Transactions on Programming Languages and Systems, Vol. 4, No. 2, April 1982.
The source for S/SL and PT Pascal can be found in S/SL and the PT Pascal Compiler Source Code. For an example of S/SL code, look at the semantic pass and the code emitter of PT Pascal or look at ssl/doc/ssl.intro.
PBP - Parts Based Programming - see the “Enhancing Programming With Parts Based Programming” video or the accompanying article, see the YouTube playlist and my substack articles with “PBP” or “Parts Based Programming” or “0D” or “Diagram” in the title, such as PBP Part Basics, How To Use Parts Based Programming - PBP, How I Execute Diagrams As Code, etc. The motherlode source repository of my ongoing PBP implementation is on github.
See Also
Email: ptcomputingsimplicity@gmail.com
Substack: paultarvydas.substack.com
Videos: https://www.youtube.com/@programmingsimplicity2980
Discord: https://discord.gg/65YZUh6Jpq
Leanpub: [WIP] https://leanpub.com/u/paul-tarvydas
Twitter: @paul_tarvydas
Bluesky: @paultarvydas.bsky.social
Mastodon: @paultarvydas
(earlier) Blog: guitarvydas.github.io
References: https://guitarvydas.github.io/2024/01/06/References.html

