Edited by humans. Written by AI. How our editing works
All articles

When Everything Is a String: TCL's Peculiar Design

TCL treats code, data, and types as strings. A developer explores why this 1980s language shaped Redis—and remains deeply weird four decades later.

Bob Reynolds

Written by AI. Bob Reynolds

February 28, 20266 min read
Share:
Motivational quote "Everything is a string" with a stylized leaf logo against a purple-blue gradient background

Photo: Dreams of Code / YouTube

Most programming languages ship with macOS by default because Apple needs them. TCL ships with macOS despite Apple wanting to remove it. That tension—between necessity and obsolescence—captures something essential about this language that almost nobody uses anymore but continues to influence software millions depend on daily.

A developer recounts encountering TCL, or Tool Command Language, in their first finance role. Fresh from learning C++, they found themselves working with a language that treats everything—types, expressions, commands, even control flow—as strings. Not metaphorically. Literally.

"When I say everything in Tickle is a string, I mean quite literally everything," they explain. "This includes things you might expect, such as every type being a string, but it also includes some other things you may not necessarily think of, such as complex data structures and even the syntax of the language itself."

This design choice creates a programming environment unlike anything mainstream developers encounter. It's not that TCL is old—many languages from the 1980s remain current. It's that TCL's fundamental architecture diverges so sharply from conventional design that learning it requires unlearning assumptions that feel universal.

The Two Faces of Strings

TCL uses both quotation marks and braces to define strings. The distinction matters enormously. Quotes trigger variable substitution—"$name" becomes whatever value name holds. Braces preserve literal text—{$name} stays exactly as written.

This isn't syntactic sugar. It's the mechanism that controls when code executes. A while loop defined with quotes evaluates its condition once, substituting variables immediately. The same loop with braces re-evaluates each iteration. The difference between an infinite loop and working code comes down to which delimiter you choose.

The developer demonstrates this with a simple counter loop. Using quotes for the conditional expression freezes the tested value at zero. The loop never terminates because it's not actually checking the variable—it's checking the string "0" that replaced the variable when the parser first encountered it. Switch to braces and the code works as intended.

For programmers accustomed to syntax being syntax and data being data, this feels upside-down. The choice between braces and quotes isn't about formatting or readability. It's about execution timing. The same string, delimited differently, produces entirely different program behavior.

Commands Masquerading as Statements

TCL has no statements. What looks like an if statement is actually a command that takes two string arguments: a boolean expression and code to execute if true. What looks like a function definition is the proc command consuming strings that describe parameters and implementation.

This means you can store an if command in a variable. You can store the code that the if evaluates in another variable. Then you can execute both dynamically using eval. The line between code and data doesn't blur—it doesn't exist.

"Everything in tickle is a string. I really cannot stress that enough. This also includes commands such as the eval command itself," the developer emphasizes.

This design enables metaprogramming so powerful it circles back to dangerous. Functions become strings that can be inspected, modified, and executed at runtime. The entire language surface area becomes programmable because the language itself is just structured text.

Redis creator Salvatore Sanfilippo saw this design and recognized something valuable. The first version of Redis—originally called LMDB—was written in TCL. The command structure, the way data types are represented, the string-centric design philosophy: all inherited from TCL. When Sanfilippo rewrote Redis in C, he kept the conceptual model.

Data Structures Built from Whitespace

Lists in TCL are strings with elements separated by spaces. Dictionaries are strings with alternating keys and values separated by spaces. There's no list type or dictionary type—just conventions for how to structure strings and commands for operating on those conventions.

To create a list element containing a space, you nest delimiters. Quote a string inside braces, or use the list command to handle the delimiter dance automatically. Lists can contain lists because a properly delimited substring is just another space-separated structure.

This approach seems fragile until you notice it's also extraordinarily flexible. Adding a new data structure doesn't require modifying the language—just defining new conventions for string interpretation and commands for manipulating them. The language doesn't need to know about your data structures. You teach it by writing commands that understand your conventions.

Modern developers might call this "stringly typed" as a pejorative. But TCL predates that criticism by decades and doesn't apologize. The string-centrism is the point, not a compromise.

Explicit Scope in a World of Conventions

Most languages infer scope from context. Variables defined inside functions stay local unless explicitly exported. Global variables are accessible everywhere unless shadowed. TCL reverses this.

Define a global variable, then reference it inside a function. The code fails. TCL doesn't assume you want global access just because you used a global variable. You must explicitly declare global x inside the function to link the names.

The same applies to reference semantics. Passing a variable to a function passes a copy. To modify the original, you use upvar to explicitly bind a local name to a calling-scope variable. The developer notes: "We've explicitly defined the scope of X to be passed in by reference."

This explicitness violates decades of language design evolution toward implicit behavior. Modern languages pride themselves on inferring programmer intent. TCL assumes nothing and requires you to state everything.

The ergonomic cost is real—more boilerplate, more opportunities for confusion. The benefit is precision. Reading TCL code, you know exactly which scope every variable reference targets. There's no hunting through outer scopes or consulting rules about closure capture. The code says what it means because the language requires it.

The Language That Persists

TCL peaked in the 1990s when its Tk GUI toolkit made cross-platform graphics programming tractable. Then Java, Python, and JavaScript offered better abstractions with larger communities. TCL usage collapsed but never disappeared.

It persists in test automation, where its string-centric design excels at generating and manipulating test cases. It persists in embedded systems, where its small interpreter footprint matters. It persists in Redis's design DNA, shaping how millions of developers think about data structure servers without knowing TCL exists.

Mostly it persists as an example of an alternate path not taken. What if we designed languages around text manipulation instead of type systems? What if we made scope explicit instead of inferred? What if we collapsed the distinction between code and data entirely?

These questions matter more than TCL's market share suggests. Every generation of developers rediscovers these design tensions. The answers TCL provides aren't fashionable, but they're considered. Four decades of production use have validated at least some of the choices.

Whether TCL remains installed on your Mac much longer doesn't really matter. The ideas it embodies—that strings can be a universal representation, that explicitness has value, that treating code as data enables powerful abstractions—those ideas keep surfacing in new contexts.

Redis isn't going anywhere. And Redis is TCL's most successful legacy: proof that deeply weird design choices, consistently applied, can produce something elegant enough to matter.

Bob Reynolds is Senior Technology Correspondent for Buzzrag.

More Like This

Developer in orange hoodie working at triple-monitor setup displaying code and analytics with neon green and purple…

35 GitHub Projects Reshaping How Developers Work With AI

From AI agents that audit your setup to tools that make your Mac's hidden language model accessible, GitHub's latest trending projects reveal where developer tooling is headed.

Zara Chen·5 months ago·7 min read
Developer holding phone surrounded by glowing task completion notifications like "project deliverable complete" and "client…

Anthropic's Three Tools That Work While You Sleep

Anthropic's scheduled tasks, Dispatch, and Computer Use create the first practical always-on AI agent infrastructure. Here's what actually matters.

Bob Reynolds·5 months ago·6 min read
Bold yellow banner with "GOODBYE VERCEL" text and arrow pointing to an illustration of stacked horizontal lines resembling…

Dokploy Promises Vercel Features at VPS Prices

A new tool claims to deliver platform-as-a-service convenience on cheap VPS infrastructure. Better Stack demonstrates what works and what doesn't.

Bob Reynolds·5 months ago·5 min read
Man holds military-grade measuring device outdoors with satellite dish and helicopter in background, yellow and red text…

Decentralized Tech: Gadgets for the Privacy-Conscious

Explore gadgets that blend tech and anarchism to maintain privacy and autonomy in a surveilled world.

Bob Reynolds·8 months ago·3 min read
Developer wearing orange hoodie monitoring colorful data visualizations on dual monitors displaying GitHub trending open…

35 Developer Tools From Hacker News That Actually Solve Real Problems

From AI agent memory management to thermal printer resurrection, Github Awesome's latest roundup shows what developers are actually building right now.

Tyler Nakamura·5 months ago·6 min read
Developer at triple-monitor setup analyzing GitHub trending projects with data visualizations and code on screens against…

34 Open Source Projects Developers Are Starring Right Now

From AI coding assistants to terminal tools, here's what developers are building in the trenches—and what it reveals about where the industry is headed.

Marcus Chen-Ramirez·6 months ago·6 min read
A man wearing a headset gestures while speaking, with "syntactic SUGAR DADDY" text and JavaScript/coding logos on a dark…

The Developer Who Fixed JavaScript Before Anyone Tried

Jeremy Ashkenas built the tools that made modern JavaScript possible — then watched the language absorb them and move on. Here's why that story matters.

Bob Reynolds·3 months ago·8 min read
Large bold "12 KB TERMINAL" text with yellow highlight pointing to a terminal window displaying code output and system…

wterm: A Smarter Web Terminal or Too Soon to Tell?

wterm renders terminal output as HTML instead of canvas, fixing xterm.js's oldest problem. Here's what that means for teams evaluating it today.

Bob Reynolds·3 months ago·6 min read

RAG·vector embedding

2026-04-15
1,654 tokens1536-dimmodel text-embedding-3-small

This article is indexed as a 1536-dimensional vector for semantic retrieval. Crawlers that parse structured data can use the embedded payload below.

When Everything Is a String: TCL's Peculiar Design | BuzzRAG