Anders Hejlsberg is one of the most influential language designers in computing history, responsible for creating Turbo Pascal, Delphi, C#, and TypeScript. Over a career spanning more than 40 years, he has shaped how millions of developers write code. This episode traces his journey from a Danish high school student fascinated by ferrite core memory to a Microsoft Technical Fellow, exploring the design philosophy behind each of his languages, the inside story of TypeScript’s open-sourcing, and his views on how AI is changing software development.
How Anders got into programming
He attended a high school in Copenhagen in the mid-to-late 1970s that offered access to an HP 2100 minicomputer with 32K of ferrite core memory, a paper tape reader, and a 1 MB hard drive. The bootloader was on paper tape because the machine had no ROM, so students had to manually type in an instruction sequence to load the OS.
He started by writing games like Lunar Lander in Fortran and HP’s version of Algol, which didn’t support recursion due to how the call instruction stored return addresses. There were no debuggers, so he had to be careful about which algorithms he used.
He loved that early machines were simple enough to see all the way down to the hardware, with no abstraction layers.
Building his first compiler
In 1979, at the Danish Technical University, he bought a Z80-based Nascom kit computer and learned assembly. He co-founded the first computer store in Copenhagen, selling kit computers, Apple IIs, Vic-20s, Commodore 64s, and TRS-80s.
All these machines came with Microsoft ROM BASIC, which was slow. He missed having a real programming language like Algol. A friend told him about Pascal, which was supposed to be simpler than Algol.
He wrote a Pascal subset compiler that fit into a 12K ROM, which could replace the Microsoft ROM BASIC. On boot, users could type and run Pascal programs directly. This was the precursor to Turbo Pascal.
Turbo Pascal
He eventually wrote a full Pascal implementation for CP/M-80 and entered a joint venture with Borland (originally a Danish company) to sell it on a royalty basis. The first version shipped in 1983.
It was called “Turbo” because it was fast, borrowing the marketing cachet of Audi’s turbo branding at the time. It was also highly interactive.
The key insight was that a compiler is not just a compiler — it’s an entire edit-compile-run-debug cycle. Turbo Pascal was designed from the start as an integrated experience, combining a fast compiler, editor, and runtime library to match the interactivity of interpreted BASIC with the performance of a compiled language.
Early versions had no debugger. When a runtime error occurred, it printed the program counter address. The compiler had a mode to stop at that address and show the corresponding source line — a clever hack without line maps or debuggers.
It was wildly successful because it was roughly 10 times better than the competition at one-tenth the price: $49.95 versus $500 for a compiler alone. The low price meant very little piracy, though Anders jokes about the “Russian site license” — one copy sold to Russia that got copied everywhere.
Delphi
The big shift between Turbo Pascal and Delphi was the move from DOS text mode to Windows GUI development. Applications now had to handle windows, events, and graphical interfaces.
Microsoft had created Visual Basic, which was impressive but interpreted and not easily extensible. At the same time, client-server database applications were booming, served by 4GL tools.
Delphi combined the rapid application development interactivity of Visual Basic with a compiled language targeting client-server enterprise apps. It featured the VCL (Visual Component Library), which allowed component inheritance, drag-and-drop form designers, and extensibility.
Delphi remained in active use for decades. The Skype application was built in Delphi, and a planned rewrite in 2012-2013 was abandoned after a year, meaning Delphi powered Skype until its decommissioning.
Joining Microsoft
Anders joined Microsoft in 1996, ostensibly as the architect for Microsoft’s Java development tools. Java had taken the industry by storm with applets, bytecode, and platform independence, and many believed it would flatten all other languages.
He worked on Visual J++ 6.0, which was a major improvement over the earlier Visual J++ 1.1 (which was essentially Visual C++ with the compiler swapped out). He brought his expertise in interactive development tools to make J++ more productive.
They also built a class library (WFC, precursor to WinForms) for building Windows desktop apps in Java, which went beyond what Sun’s Java offered on Windows.
The Sun-Microsoft lawsuit and the birth of C#
The Sun-Microsoft lawsuit over Java effectively killed J++ as a viable platform. Companies wouldn’t bet on a language that had been enjoined by a judge. This made it clear that placing a development platform bet on technology licensed from a competitor was not a sustainable strategy.
At the time, Microsoft’s main development tools were split: Visual Basic (easy to use, rapid development, but slow and not extensible) and C++ with MFC (powerful and expressive, but difficult). Developers wanted both.
There was also demand for modern features like garbage collection, exception handling, and a more object-oriented, component-oriented model — things Java had popularized.
This led to the simultaneous creation of .NET (a language-independent runtime) and C# (a language designed to appeal to both VB and C++ users and compete with Java).
Building C#
The overarching design goal was the power and productivity of C++ with the ease of use of Visual Basic, plus modern features like garbage collection, exception handling, a unified object system (where anything can be assigned to object), self-describing types for reflection, and first-class support for properties, methods, and events as the building blocks of components.
C# was also designed from the start to be standardized and given to a standards committee.
The language design team was small — six to seven people, all of whom had built or worked on programming languages before. They met three times a week for two hours, starting from scratch. Everyone was expected to shoot down new ideas; only ideas that survived collective criticism were adopted.
Anders wrote the language specification in parallel with the design meetings, while a separate team implemented the compiler in a subset of C++ (“C plus minus”). The compiler was not self-hosted in C# until the much later Roslyn project.
Early IDE support was rudimentary — basic syntax coloring and statement completion — implemented as a separate “mini language service” alongside the real compiler. As features like generics and LINQ were added, maintaining two parallel implementations became a drag, which ultimately led to the Roslyn project: a single compiler that functions as both a command-line tool and an interactive IDE service. TypeScript was later built the same way.
Internal dogfooding was critical: the .NET Framework team switched from a hacked-up C++ to C# for their implementation, and other internal teams used it, providing feedback. The cycle from start (late 1998) to public beta at PDC 2000 was relatively short.
Async/await
Many languages use cooperative multitasking with an event loop. The problem is that long-running work can’t easily yield back to the event loop mid-execution without manually building a state machine, which is notoriously difficult.
Async/await solves this by letting the compiler generate the state machine. The await keyword marks where the function should yield. When the awaited promise completes, execution resumes. The compiler handles moving stack state to the heap and generating the switch statement.
This gives the illusion of sequential code while the compiler does the painful transformation. It avoids the callback-style programming that JavaScript suffered from.
An alternative is OS threads, but they come with preemption, heavyweight context switching, and multi-threading complexity in UIs. Go’s goroutines (green threads) are another approach that avoids “function coloring” — the problem where async functions can only be called from other async functions, creating a cascading color change up the call stack.
Async/await was adopted by JavaScript, Python, Rust, and many other languages.
The rise of JavaScript
In the early 2000s, several things converged: Google’s V8 engine made JavaScript performant; HTML5 enabled real UIs in the browser; and the iPhone-driven device revolution meant diverse form factors all running browsers with JavaScript. The real cross-platform language turned out to be JavaScript, not Java.
Externally and internally at Microsoft, teams were building larger JavaScript applications. A trigger event was when the Outlook.com team asked the C# team to productize “ScriptSharp,” a cross-compiler that compiled C# to JavaScript so developers could use a grown-up language and Visual Studio for browser apps.
Anders’s response was: rather than telling people to write in a different language, fix JavaScript itself. JavaScript is a decent language — Brendan Eich got functions as first-class objects right — but it lacks a type system, which is essential for scalable tooling.
Building TypeScript
The idea was to create a superset of JavaScript that adds an erasable type system, then use that foundation to build great tooling — statement completion, refactoring, go-to-definition, find-all-references.
Open source was non-negotiable. There was zero chance the JavaScript ecosystem would adopt a proprietary Microsoft language. But getting approval inside Microsoft was difficult — the company’s DNA under Steve Ballmer was still anti-open source.
Anders and Steve Lucco (co-inventor of TypeScript) insisted on open source. They got approval but had to host on CodePlex, Microsoft’s open source repository where essentially no one went. For the first two years, it was “crickets.”
In 2014, they moved to GitHub, which transformed the workflow from merely open source to truly open development. Issues, PRs, and the entire development process moved to GitHub. This is what made TypeScript as successful as it became.
By November 2025, TypeScript became the most popular language on GitHub’s Octoverse report. Anders attributes this to better tooling enabled by the type system. VS Code (written in TypeScript) was an early adopter and close collaborator. The interplay between TypeScript and VS Code also led to the invention of LSP (Language Server Protocol), now used by nearly every tool vendor.
How the TypeScript compiler works
The pipeline is: lexer/scanner (text → tokens), parser (tokens → abstract syntax trees), binder (attaches symbol information and builds control flow graphs), type checker (the largest stage, checks semantic correctness), and emitter (erases types and optionally down-levels newer ECMAScript features to older syntax).
The emitter is simpler than in most compilers because it doesn’t generate machine code — it just strips type annotations and outputs JavaScript. Early on, down-leveling (e.g., converting classes to constructor functions) was a major feature, but as browsers became evergreen, this became less important.
The key architectural difference from traditional compilers is that the TypeScript compiler is built for highly interactive use in IDEs. A program being typed is perpetually broken, yet the IDE must answer questions (e.g., what members does this type have?) within 200 milliseconds, even across 500,000 lines of code.
The solution is extreme laziness and deferral: only rebuild the AST for the file being edited, resolve types starting from the current position, and reuse everything else. This is a fundamentally different way of writing compilers than what textbooks teach.
JavaScript’s strengths and weaknesses
Anders likes functional programming and wishes JavaScript had let expressions within expressions (like OCaml’s let ... in), allowing symbolic naming of temporary results without breaking out of expression context. “Do expressions” have been proposed but are taking a long time.
JavaScript’s gradual typing is TypeScript’s most interesting feature. Unlike languages that require types everywhere (because they use them for code generation), TypeScript’s types are purely for development experience and checking — they’re erased at runtime.
This means TypeScript doesn’t need to prove 100% type correctness. With recursive structural types, some cases are infinitely recurring and can’t be fully analyzed. TypeScript can say “we’ve checked four levels deep, that’s good enough” because JavaScript’s runtime is well-defined regardless. This enables language features that no statically-typed language could offer.
How Anders uses AI
His team is currently porting TypeScript to native code (a year-and-a-half-long project). AI wasn’t capable enough at the start but is now used for: code review of PRs, implementing simple issues, porting a backlog of PRs from the old codebase to the new native compiler, and writing tests.
AI is good at “surface-y” work and drudgery like test generation, but the team is not at a point where it absolves them from understanding what they’re doing. At the language/compiler level, deep understanding of types, symbols, binding, parsing, and data structures is still essential.
He notes that AI is inherently stochastic and non-deterministic, yet applications must be deterministic. This is why programming languages remain essential — they’re where “the rubber meets the road.” He observes that AI agents often write Python programs when asked data-related questions, effectively converting non-deterministic queries into deterministic computations.
What language features work well with AI
The language most suited for AI is the one AI has seen the most of in its training data — JavaScript, TypeScript, and Python benefit from this.
TypeScript’s combination of explicit types where there’s no context and type inference where there is context works well for AI. Forcing type annotations everywhere would make AI get it wrong more often and repeat itself. Inference follows DRY and reduces token usage, making AI more efficient.
Locality is increasingly important: clearly stated imports, self-contained modules whose protocols can be extracted from a single file without understanding the whole codebase. This reduces context window size and makes modules easier to summarize.
AI is beginning to become aware of language services but currently relies on grep and awk rather than semantic search. LSP implementations already provide the needed services but may need to be made more accessible to AI (e.g., as command-line tools). A server keeping a project hot and serving semantic queries to AI, then dumping it after 10 minutes of inactivity, is a plausible architecture.
How software craftsmanship is changing
Developers are increasingly becoming project managers overseeing armies of junior programmer agents. The craft shifts from writing code to reviewing code, building architecture, and overseeing work.
Anders personally finds less enjoyment in reviewing code than writing it, but the review process could be improved — more pedagogical presentation of diffs, AI-generated commentary explaining changes, guided walkthroughs.
He pushes back on the idea that AI will eliminate programmers. Vibe coding works until it doesn’t, and then you have no idea what’s going on. The responsibility for a program always lies with the programmer, not the AI. AI is a tool for productivity, not a replacement for understanding.
What developers care about
Developers care about being productive and “in the zone” — where the tool feels like an extension of their fingertips. This is why they become so attached to their tools and languages, almost religiously.
For a language designer, the language is never just the language — it’s the entire experience. The compiler is not the product; the product is the whole edit-compile-run-debug cycle. IDEs and languages go hand in hand.
Performance and efficiency
Whether efficiency matters depends on the application domain. For compilers, tooling, and high-frequency trading, performance is king. For many other applications, hardware is so fast that even 10x slower code is imperceptible, and optimization isn’t worth it.
His team is spending a year and a half moving TypeScript to native code specifically because they care about performance.
Anders’s tool stack
He’s a Windows user with a Lenovo P1 laptop (15-16 inch, OLED screen, portable). He uses VS Code exclusively for coding and GitHub for collaboration. For AI coding assistants, he uses the GitHub Copilot integration within VS Code.
LLMs are still limited for compiler work — good at surface-level tasks but not yet capable of reasoning about the deep relationships between types, symbols, binding, parsing, and efficient data structures. Also, there are far fewer compilers in AI training sets compared to React GUI apps.
A 30-year career at Microsoft
He’s been at Microsoft for 30 years and working on languages for 40. What keeps him is a love for developer tools and the algorithmic complexity of language design. Building from the bottom up with fewer dependencies suits him.
Language design is a long play — it operates in 10-year cycles. Version 1 has issues, version 2 fixes them, version 3 is great, and then you have to convince people to adopt it. Having Microsoft’s resources and commitment behind a language is a rare opportunity.
Microsoft is fundamentally a developer-focused company, which aligns with his values of doing honest work that developers and enterprises pay for directly.
Book recommendation
He always recommends Niklaus Wirth’s Programs + Data Structures = Algorithms (1976), which is available online. It was a revelation for him — it taught him hash tables and how to construct a compiler. It’s light on symbolism, rich on examples, and still relevant today because the basics of the discipline haven’t changed much in 50+ years.