It was interesting talking to Anders Hejlsberg, the creator of TypeScript and C#, about all the technical details behind rewriting the TypeScript compiler in Go.
I had a lot of questions about why they chose Go (vs Rust) and if they used LLMs in the rewrite. Turns out they used LLMs much less than expected in the rewrite. He explained why in the conversation.
Anders has strong takes on how AI will impact software engineering so I made sure to run all the famous takes I’ve seen on Twitter to see what he thought like:
Will AI write all the code in ~1-2 years?
Will AI replace junior engineers in a few years?
Will you still need to use an IDE by the end of the year?
And also I asked him why his opinion seemed to be so different from the more AI-pilled companies like the labs. Hope you enjoy the episode, full transcript below as usual if you want to skim.
Check out the episode wherever you get your podcasts: YouTube, Spotify, Apple Podcasts.
Timestamps
00:48 - Why write a compiler in JavaScript
07:29 - Why rewrite the compiler in Go
14:49 - LLMs for large migrations
20:12 - Why Javascript is so popular
26:32 - Why ever use Javascript on the backend
32:59 - What it takes to build a programming language
37:06 - Will there be fewer languages in 10 years
42:57 - Hands on engineering vs delegation
49:14 - Why fast tooling matters more now
51:16 - AI software engineering predictions
58:52 - The most technically challenging work
01:02:04 - Top book recommendation
01:03:50 - Advice for his younger self
Transcript
00:48 — Why write a compiler in JavaScript
Ryan:
[00:48] The big thing that we’re going to talk about here is obviously TypeScript 7 with the native rewrite. And the first thing that I think of when I see this was I didn’t even realize that the compiler was written in JavaScript to begin with because I don’t usually think of compilers being written in high-level dynamic languages.
Anders:
[01:09] Yeah, no.
Ryan:
[01:11] So why was TypeScript written originally, the compiler written in JavaScript?
Anders:
[01:17] No, it’s a good question. And honestly, if you had told me before the TypeScript project started that, “Anders, you’re going to be writing compilers in JavaScript,” I’d be like, “No, no, I’m not.” But I mean, the original prototypes for TypeScript, the Strada project, as it was called in the very early days, were actually written in C because it was like an adaptation of the parser, the JavaScript parser that we had in Internet Explorer and whatever.
[01:49] And then we’ve moved to JavaScript, but we wrote it sort of C# style. But why did we go with JavaScript? Well, I mean, if you can self-host in the ecosystem that you want to be a part of, then that is just dramatically better than putting yourself outside the ecosystem and trying to target that ecosystem. Do you know what I mean? Because by writing it in TypeScript, we were also daily users of TypeScript and daily users of the tooling that we were building.
[02:21] And whenever something didn’t work right, we knew it immediately. And whenever something didn’t perform right, we knew it, and so in the early years, it was a huge boon, I think. And then, of course, JavaScript runs everywhere, right? And that meant automatically our compiler could run on every platform, anywhere, even in the browser. Had we gone with a native code solution at that time, it wouldn’t have been possible to run it in the browser.
[02:49] Now we have WebAssembly or WASM, but that didn’t exist at the time. Right. So it was a meaningful choice. And honestly, at that time also, people didn’t really realize how fast JavaScript had gotten. I mean, it used to be very slow, and then Google did all of their excellent work with V8 and got it to within 2 or 3x of native code, which is pretty darn impressive. And it was like full well possible to write compilers in JavaScript, and you could even get them performant because often it’s the algorithms that determine how performant you are.
[03:33] It isn’t necessarily the runtime environment. Right. I mean, it’s a combo. But yeah.
Ryan:
[03:38] Is there anything unique about the TypeScript compiler? I think of a compiler, I think of Clang or one of those ones that is used for maybe C or those static languages. What’s unique about the TypeScript compiler when it was written in JavaScript compared to these native compilers?
Anders:
[04:00] I think there are a couple of things that are pretty unique about TypeScript‘s compiler. First of all, it doesn’t target machine code, it targets JavaScript, and some people call that a transpiler. And in a sense, the compilation phase is mostly about removing the type annotations and turning your TypeScript back into JavaScript. Right now, in the early days, also an important part of the compilation process was to downlevel your JavaScript, meaning all of the runtime environments at the time were not evergreen.
[04:36] And sometimes people were lagging multiple years behind on which level of the standard was implemented. And for example, when classes got standardized, most JavaScript runtimes didn’t implement classes, but it turns out that you can downlevel to constructor functions, transform the code. And so part of what we did was this transformation, downlevel transpiling of the code. But then, of course, the type checking is the big thing that we do.
[05:06] And the type checker in TypeScript is also quite unlike any other type checker in other compilers. Typically, type checkers exist in compilers to guide the code generator because you want to know: are we dealing with a float or an int or a string here so we can generate the correct machine instructions for that data type, et cetera, et cetera. That’s not the case in TypeScript. In fact, since we erased the types, the types have no impact whatsoever on the runtime behavior of the code.
[05:40] They purely exist for tooling sake and for the developer’s sake and to guide things like statement completion and refactoring and code navigation, which is a whole different thing. Also, they don’t necessarily have to be there. And so TypeScript has a gradual type system. You can sort of have half of your code have types and the other half is just anys that we don’t check. Now very few languages have anything like that.
[06:13] So it’s a very different compiler in that sense and a very different language in that sense. That actually made it fascinating to work on because we were solving problems that no one had solved before.
Ryan:
[06:25] I know a lot of compilers, they take the higher-level code and they typically apply optimizations as well. Maybe they unroll loops or they get rid of duplicate instructions, simplify things. Does anything like that happen in the TypeScript to Java compilation process?
Anders:
[06:44] Very little. Like I said, when we do the downleveling, there are some transformations that go on that are complex. But it is less and less the thing that’s important about TypeScript. In fact, a lot of people use TypeScript only for the type checker, and then they use some bundler like esbuild or SWC or whatever to package their app, erase the types, do whatever needs to be done in order to make it runnable in the browser.
[07:15] And so we’re not really there to optimize your code for runtime. We’re there to make you more productive as a developer or make AI more productive as a developer.
07:29 — Why rewrite the compiler in Go
Ryan:
[07:29] So with the native rewrite of this originally fully JavaScript compiler, what was the problem you were trying to solve with the rewrite, and why did you end up rewriting it in native code?
Anders:
[07:43] Well, the problem we were trying to solve is real simple: performance and scalability. JavaScript was never really optimized for compute-intensive workloads like compilers, right? JavaScript is more about creating UI that runs in a browser. It was originally intended for just maybe 100 lines of code, but now, of course, it’s gotten to be a lot more. But it’s not a place that you would optimize for the kind of workload that we are.
[08:16] So in JavaScript, first of all, you pay a 2 to 3x perf penalty compared to native code. I mean, it depends on the workload, but if you’re doing compute, that’s about where it’s at. And then secondly, in JavaScript there are a lot of restrictions around use of concurrency. JavaScript was always engineered, in fact, to be a single-threaded language. That’s why we have callbacks and async and whatever.
[08:44] It’s because you can’t spin up threads, and that’s a good thing. Mostly because concurrency in a language with mutable data is very, very hard, because you can have races and deadlocks and all of this good stuff, right? That’s why functional programming languages are easier with concurrency, because all the data is immutable, and it’s much easier to reason about. So JavaScript doesn’t give you access to concurrency other than web workers.
[09:15] But web workers can’t share data between each other other than by remoting it. So you can have one web worker compute something, but if it wants to give it to some other web worker, it has to turn it into JSON, or it can’t just hand it objects. And that means you can’t have one worker compute some data structure and then have someone else use it. In other words, you can’t have shared memory concurrency.
[09:41] And really that’s what we wanted in order to gain all of the perf that we were leaving on the table by not utilizing multicore CPUs that everyone has today, right? Because Moore’s Law has stopped giving us faster CPUs, it’s giving us more CPUs, and we got to find ways to use them in our compute-intensive workloads, or else we’re leaving money on the table. And so we were leaving money on the table in multiple ways, right?
[10:08] And so native code, and that was why we looked for a language that would get us out of both of those binds. It had to be native and it had to have access to shared memory. Concurrency.
Ryan:
[10:21] I saw for the language choice you went with Go. And when I think of all the systems languages, the ones that are often hot are maybe Rust or Zig, why did you choose Go for the native rewrite?
Anders:
[10:35] I think the decision process was actually pretty structured. The first decision we made was we’re not going to rewrite, we’re going to port. Because only by porting can we preserve the semantics and the algorithms and the exact behavior of our existing compiler, which everyone depends on for backwards compatibility. Now, we could have cleaned the slate and started completely from scratch, but we would have come up with a different language in the sense that it would give you different errors or behave differently in certain situations where it has to make choices between multiple possibilities and what have you.
[11:15] So we wanted to port that meant our code makes certain assumptions. Our code, for example, assumes the existence of garbage collection. It assumes the existence of first-class treatment of functions. You can have functions within functions, and you can close over outer state and so forth. As we evaluated all of these, Go was the one that checked the most boxes. It gives us very robust and mature native code generation on all major platforms.
[11:53] It has garbage collection and it has excellent access to shared memory, concurrency. And those were the high-order bits that we wanted to check. And every other language had something that kind of worked against those objectives. So for this particular workload, Go was the right choice for us. And it’s worked out well.
Ryan:
[12:16] If you think about Rust, what didn’t it have that if it had it, you would have picked it?
Anders:
[12:22] I mean, I think there are two things. It doesn’t have garbage collection. It’s done manually, or it’s done through the borrow checker. But the borrow checker doesn’t allow circular data structures. And our compiler is chock full of circular data structures. We have trees with parent pointers, we have types that are recursive, we have symbols that refer. I mean, it’s everywhere. And like I said, if we had chosen to rewrite, we could have probably solved all of that.
[12:54] But it wouldn’t have been just porting the code. It would also have been solving a whole bunch of new problems that we had bought ourselves by going that route. We tried, and it just wasn’t feasible. And so we were just trying to optimize for doing as little work as possible to get us to the payout. And honestly, Rust is no better when it comes to the quality of the generated code or the concurrency gains that we could have gotten out of it.
[13:27] Go is just great. I mean, so we got all the bennies for less work by going that route.
Ryan:
[13:35] I know some languages, when you say they’re garbage collected, there’s something in the language itself that is doing garbage collection. But there’s also independent libraries that can provide garbage collection, right?
Anders:
[13:52] There is, but it often comes with a whole bunch of restrictions, and it doesn’t necessarily come with the safety guarantees that we were looking for. I mean, Go is type-safe and memory-safe, meaning that you don’t get to just have stray pointers or whatever. With Rust, you can do ref counting or you can do all sorts of different strategies, but there’s always that little bit of unsafe where you have to do this in order to make it all work.
[14:26] Where if garbage collection is engineered into the language, it really is a separate concern that is you don’t have to do anything special. I mean, of course, you have to not hold on to data that you no longer need and whatever. But that’s true of ref counting as well, right? But it is inherent in the language.
14:49 — LLMs for large migrations
Ryan:
[14:49] When you ported it from JavaScript to Go, I’m curious how much LLMs were used in that process, because I know famously there’s some major projects that have been doing rewrites of their entire codebase. I know there’s this JavaScript project called Bun that rewrote everything from Zig into Rust, so it seems like a pretty useful tactic. And I’m curious if you leveraged that in this process.
Anders:
[15:16] Not a whole lot, but it also has to do with timing. We started this project two years ago, and two years ago, LLMs were nowhere near as good as they are now. I mean, that’s how crazy fast it’s all moved, right? So what we did, though, is we certainly had a bunch of tools that aided us in the port. I’d say the prototypes we wrote, the scanner and the parser we wrote manually. And at that point we could convince ourselves, wow, we can actually get 10x out of this.
[15:51] Now what do we do with the rest of this code base? What we did was we wrote a tool that syntactically translates TypeScript into Go, this code that comes out of it. It has no syntax errors in it, but it doesn’t compile either because it’s full of... It uses types as if they were TypeScript, which they’re not in Go. And so all of that had to be refactored. We had to redo all the data structures or whatever, but we got the same code base out of it, and then we could sort of bang on that, and then in a more localized fashion, maybe use AI occasionally to help us do the transformation.
[16:29] So it was sort of manual and automated and a little bit of AI. Now, if we were to start the project today, would we do it differently? Possibly. Although I will say, if we just let AI loose on what is it, like half a million lines of code that we have in the old compiler, or somewhere between half a million and a million, and asked it to translate it all, well, I don’t know that that would absolve us from then having to go in and carefully examining every line that came out of it to make sure that there were no hallucinations.
[17:04] Right. Unless you have 100% perfect test coverage, you probably still got to go check all of that. Now, I think a better approach, quite honestly, would be to enlist AI to write a program that helps you translate from TypeScript to Go, because at that point you can park the stochasticness in that program and then you can get deterministic behavior whenever you run the program, which means you get the same transformation every time you run it.
[17:35] That’s always the thing about AI that people forget: it’s not deterministic. So you can’t really trust that it’s going to do the same thing twice. We might have done it that way, but AI was not ready to do it at the time. Now, that doesn’t mean that we don’t use AI now down the line. We use AI a lot in our internal processes around the compiler, as everyone does, right? Help it to write tests and to move pull requests and what have you.
[18:05] And whenever an issue is logged, first thing we do is put Copilot on and see if it can fix it for us, right? I mean, so, yeah, in that approach.
Ryan:
[18:13] where you use the LLM to generate tooling and then the tooling is deterministic, but you’d still have to validate that thing.
Anders:
[18:23] Yes, but that’s a much smaller surface area that you have to validate, right? And honestly, I’ve seen that even with friends. We did some trip together, and there was some accounting of it. Well, he paid for the hotel rooms and we paid for this and whatever, and we needed to sort it all out, right? So, okay, well, here’s what all the costs were, and here are the pieces, and have AI fix it for us, right?
[18:46] Or like tell who owes who what. And it very authoritatively came up with the wrong answer, right? Because it just forgot about some of the settlements, right? But if we had asked it to write a spreadsheet, which is really just a program, right, then we would have gotten the right answer because it’s very good at writing programs. So it’s kind of funny how sometimes you don’t ask AI for the answer, you ask it for a program that computes the answer.
Ryan:
[19:17] What are the potential benefits that you left on the table by doing a port instead of a full rewrite?
Anders:
[19:23] To be honest, I don’t think there are any, and I don’t think we would consider a rewrite. We were quite happy. We’re quite happy with the way this codebase works. I don’t think we’re leaving any money on the table currently. And as I said earlier, rewrites are toxic often for ecosystems, because they sacrifice compatibility, because you never rewrite and you never get back to exactly what you had before, right?
[19:54] Oh, but in the name of making it better or prettier or whatever, we change this and that and the other, right? And then while all the users get to suffer through that, right? So backwards compatibility is super important if you want to keep your ecosystem happy. And we do want that.
20:12 — Why Javascript is so popular
Ryan:
[20:12] In studying for this interview, I just keep reading about JavaScript and the strange semantics of the language. And I think throughout my career too, people have typically not been super satisfied or happy with JavaScript for some reason or another. My question is, why is it so popular despite that?
Anders:
[20:36] First of all, I don’t think JavaScript is as bad a language as some people make it out to be. I will say in the three, what, three, four weeks that Brendan Eich had to create this language back in the mid-90s, he did a lot of things right, and thank God that he had been educated on functional programming and got first-class functions done, right? Where you can have functions within functions and the inner functions can access the outer function state and you can pass functions around as first-class values.
[21:09] That is super powerful. JavaScript actually got that very right. Now there are some quirks in the language too. All of the automatic conversions and all of the bizarre differences between double equals and triple equals just drive everyone mad. But that’s exactly what type checkers are happy to do. They can ferret out all the little differences because they understand all the deep semantics of the language that no one seems to be able to keep in their mind.
[21:39] So I think that’s part of why TypeScript has become so popular, right? It can actually truly bring out the best parts of JavaScript and leave the bad stuff behind. And of course you can’t. The thing about JavaScript is it is the cross-platform language, like even Java, that was engineered and intended to be the way to write cross-platform applications. It’s not really cross-platform.
[22:06] It doesn’t run in the browser, I mean, it doesn’t run everywhere, right? JavaScript runs everywhere. So there are a lot of reasons why you should like JavaScript. And with TypeScript, I think we’ve managed to sort of capture all the badness and park it.
Ryan:
[22:27] I saw there were some projects. I don’t know if you’re familiar with Dart or CoffeeScript, and it seems like these were some efforts to replace JavaScript or improve it, but they’re not popular today. So I’m curious what happened.
Anders:
[22:44] I mean, I think CoffeeScript was mostly a different syntax for JavaScript, so it doesn’t really change the semantics, and it didn’t provide any additional tooling or whatever. And Dart was also, in a sense, about fixing JavaScript. Right, but if you can fix something by fixing it instead of trying to replace it with something else, then you’re doing the ecosystem a much bigger favor, I think.
[23:16] Right. And that’s what we set out to do with TypeScript. We weren’t trying to change JavaScript; we were trying to improve JavaScript. And I think that’s ultimately why we succeeded.
Ryan:
[23:28] I mean, in this new age where it’s very feasible that maybe AI could rewrite code bases, I imagine people will start to go toward the desired languages rather than the ones that are the incumbent languages. And I’m curious if you think that JavaScript might become less used in the future.
Anders:
[23:51] See, I don’t think so. What I’ve observed is that AI is best at the languages it’s seen the most of in its training set. AI gets trained on all the code that exists in the world, which means there’s an awful lot of JavaScript, an awful lot of TypeScript, an awful lot of Python, and therefore AI is good at JavaScript and TypeScript and Python. It is less good at my favorite little language that I just invented.
[24:22] In fact, there’s none of it in the training set, which means you have to sacrifice God knows how many tokens in the prompt to teach AI the language before you can even ask it a question about the language. Do you know what I mean? So in that sense, I think incumbent languages are actually, if anything, going to flourish because of AI. And we’re sort of seeing that right now with TypeScript too. Right.
[24:47] There’s a noticeable knee in the curve of TypeScript adoption that coincides with the advent of AI. I do think the incumbent languages are actually, if anything, getting stronger.
Ryan:
[24:58] What percent of all JavaScript is written in TypeScript?
Anders:
[25:04] Well, so in the last year, TypeScript became the number one used language on GitHub. So there is JavaScript more than JavaScript. So more than 50% on GitHub at least is written in TypeScript. So we’re actually larger now than the language that we set out to improve.
Ryan:
[25:28] Wow.
Anders:
[25:29] Yeah. And larger than Python.
Ryan:
[25:31] If you were to just draw that out in the future, do you think that eventually TypeScript would become the default and almost 100% of all JavaScript would be typed?
Anders:
[25:41] Well, certainly. I mean, if you’re having AI write it, I almost challenge you to find a tool that writes JavaScript. They all write TypeScript because it helps AI write better code, because the type annotations guide the LLM toward writing, or to write, making fewer mistakes, and the ability for us to statically validate the code before you run it. I mean, that’s the distinction, right? The only way you can validate JavaScript is by running it, which means you have to set up a runtime environment, which might not be possible for AI to do because AI lives in a sandbox, but AI can run through tools, the compiler, and check the code that it just generated and be told, oh, you made a mistake.
[26:27] Oh, well, let me fix it then before I even tell anyone that I made the mistake. Right?
26:32 — Why ever use Javascript on the backend
Ryan:
[26:32] After learning about this 10x improvement and performance from rewriting in native, it makes me wonder why anyone would use JavaScript on the back end. Why not just always use native languages on the back end?
Anders:
[26:48] Well, it depends on your problem, I think, because the thing that overlooks is what kind of thing am I going to write on the back end? There are an awful lot of very, very good web server frameworks, for example, that use TypeScript or JavaScript, right? So if there are frameworks in your ecosystem that get you to a solution quicker than if you had to write that because your native language wasn’t really intended to target that particular community.
[27:21] So I think it very much depends on what your problem is affinitized with. And often performance of your code isn’t the bottleneck. I mean, look at Python, right? It’s used to basically script all of the LLM training in the world, right? I mean, a lot of that code is ultra time critical, but that’s written in native code, right? And then you use Python as the orchestration language, and in a sense, in a web server, TypeScript is just an orchestrator of talking to a database and doing this and that. And the things that ultimately control the performance of applications like that aren’t necessarily whether that inner for loop is running as native code or not.
[28:12] Which actually it is because of the JIT anyway, right? I mean, so measure first and then make decisions, right? Because you always get surprised when you measure, when you talk about how much faster it was to.
Ryan:
[28:24] One of my immediate thoughts is, why wasn’t it done sooner?
Anders:
[28:33] At the time we started TypeScript, I don’t know that we had ever envisioned that people would be writing projects that are the size of the projects that people are now writing in TypeScript, right? Visual Studio Code is like 2.3 million lines of code. I mean, we have in-house projects that are over 10 million lines of code, which is insanity. We would have just at the time gone, well, that’s clearly no one’s ever going to do that, right?
[29:01] But that was a decade ago, more than a decade ago, right? We started in 2012 with the TypeScript project, and the world looked very different. And so gradually, people have started writing larger and larger and larger projects, right? And at the same time, our compiler has gotten smarter and smarter. We’ve added all sorts of cool features like union types and discriminated unions and control flow analysis and blah, blah, blah.
[29:26] And all of these things make our type checking even better. But it also makes it go a little slower every time we add a new feature, right? In fact, our TypeScript 6 runs only about 50% of the speed of TypeScript 1.5, for example. But TypeScript 1.5 also did a whole lot less. So projects have gotten bigger and the compiler does more. All of which detract from your effective output. And as I mentioned, Moore’s Law also, unfortunately, stopped delivering faster CPUs, and JavaScript keeps you from taking advantage of the additional cores.
[30:02] And it’s not clear that we could have foreseen all of that, right? But it’s just the way it panned out, right?
Ryan:
[30:10] OpenAI, Anthropic, Cursor, and Vercel all use this product to make their lives better. And the problem it solves is when you’re building SaaS or an AI product and you want to sell to other companies, there’s all these requirements you need to meet. There’s SSO, there’s SCIM, there’s RBAC, there’s audit logs. These are all things that take time to integrate but aren’t the main focus of your app. WorkOS is an API layer that lets you meet all of these requirements in just a few lines of code.
[30:40] So let’s say you have a new SaaS product and you want to sell to other companies. WorkOS will solve all of these critical feature gaps for you. You can check them out at workos.com to learn more and get started. And I appreciate them for supporting my work and sponsoring this podcast. Jira by Atlassian isn’t just for tracking work anymore. Now you can pick your favorite AI agent to assign tasks to, and they’ll get access to the rich context that’s already in Jira.
[31:07] When the agent is done, it surfaces a pull request. That way you can get more done with your favorite agents, all in one place. Learn more at jira.dev. That’s J I R A. D E V. Appreciate them for sponsoring the podcast. And back to the show. I first became a software engineer and I went to start working at Facebook. At the time they had this popular framework called Flow, which was doing type inference on top of JavaScript.
[31:37] It was this thing that would take a long time, and then I’d never hear about it these days. So it sounds like TypeScript won, if there was a competition to type in.
Anders:
[31:46] There was a bit of it, yeah. In the early days, I think the thing that worked for us was actually the fact that we were self-hosted, which made it a lot easier for the community to contribute to the project. Flow was written, as I recall, in OCaml. And so in order to contribute to Flow, you had to go learn a whole different way of programming in a different language. Right. And Flow also did not focus all that much on IDE-based tooling, which we knew full well going in.
[32:22] We’re writing a compiler, but we’re not writing a compiler in order to generate machine code. We’re writing it to make better tooling. That was why we wrote it right there, hand in hand with our compiler. We had a language service. It was deeply integrated into Visual Studio, Visual Studio Code, all sorts of other editors through an open protocol, and that’s where the problem that needed solving was.
[32:47] I mean, it’s nice to have a type checker, but boy, you want that. You also want statement completion. You want red squigglies, you want it interactive, right?
32:59 — What it takes to build a programming language
Ryan:
[32:59] So I know in your career you’ve, you’ve worked on multiple programming languages. What does it take to build a programming language?
Anders:
[33:07] Well, first I’ll say that the world needs another programming language. Like it needs another hole in the head. I mean, it’s like you kind of got to be a certain kind of person to even embark on it to begin with, right? It’s a super fascinating area of computer science and it’s one that’s been around ever since the beginning of computers. Now every compiler, every language has a whole bunch of things you need to understand, like parsers and scanners and lexers and code generators and whatever, right?
[33:43] But that’s sort of the mechanics of implementing the language and then there’s the design of the language, sort of the art of making it feel right, whatever, right? And I think you sort of have to master both. And then you also got to appreciate that like every new language is actually only 10% new. And then it’s 90% the same drudgery that every other language has to go do. And so be prepared for a lot of work that maybe isn’t as interesting, you know, and then finally maybe I’ll say that, you know, like, never forget there that you stand on the shoulders of giants.
[34:24] I mean, in order to make a great programming language, you got to understand a bunch of other programming languages first and understand all the, all the distinctions between the different styles of programming like procedural and object oriented or functional or what have you. And then last but not least, it’s like it’s a long game. I mean, it is probably a longer game than anything else. I mean, like every language project I’ve worked on, I’ve worked on each of them for at least 10 years and shipped multiple versions.
[34:58] And it’s really never until version three that it truly starts to get okay, do you know what I mean? And it just takes an incredible amount of devotion to that. So you gotta really not be the type that tires of a problem quickly and then moves along that you’re not meant to do language design. And you see that too when you talk to language designers in the industry. They’ve been doing it for a long time.
Ryan:
[35:23] You mentioned those two parts. There’s the objective pieces that you need to implement and then there’s the art of the design and making the language, I guess, ergonomic for developers. When you think of that second part, that art, and you look at other programming languages, are there any that you admire outside of the ones that you’ve worked on?
Anders:
[35:45] Of course, learning and fully appreciating the beauty of functional programming has been very educational. I mean, because it really is a different way of thinking about programming, a way of thinking of programming that’s much closer to math than it is to machines. And I think there’s a lot of incredible goodness that has come from that. And honestly, Even in building TypeScript project, large portions of the TypeScript compiler are written in a highly functional style and work on immutable data structures that are then.
[36:25] Now, because of shared memory, concurrency can be shared between different threads or processes that don’t mutate the data and therefore they can share one data structure that’s incredibly powerful. But mastering this, like writing islands of pure functional programming inside an imperative program and putting it together with concurrence, I mean, it’s complex, but I think functional programming has brought a lot to the world.
[36:55] I know object oriented programming as well, but I wouldn’t single out any particular language. Every one language you come in contact with, you learn something.
37:06 — Will there be fewer languages in 10 years
Ryan:
[37:06] You mentioned the world doesn’t really need more programming languages. And if you think 10 years from now, do you think there will be less programming languages than there are today?
Anders:
[37:19] It’s hard to say. But like I said, AI tends to favor the incumbents. Right? And I do think, and I think this has been true even before AI, the bar keeps going up for what it takes to successfully implement a programming language and create an ecosystem around it. I mean, it used to be, oh, you just need a compiler. Well, you also kind of need tooling now. I mean, you need a language service, you need debuggers, you need profilers, you need frameworks and libraries, you need code generators that can target all sorts of.
[37:59] I mean, it’s like it just keeps getting harder and harder to get all the way there.
Ryan:
[38:08] When you think about all those pieces, really, they’re all for the people. I mean, the IDE and the types. I mean, the computer looks at that too, but it’s so that we can read source. Maybe one day the LLMs will generate machine code directly.
Anders:
[38:28] I wonder. I think LLMs are better at what they do when they don’t have to repeat themselves a lot. I think, like when a program is expressed in text, it is closest to its sort of ultimate condensed meaning and representation. Right. If you translate it into machine code, there’s an awful lot of noise in that machine code. Like all of the instructions, like, half of the instructions are memory addresses that have absolutely no bearing on what’s going on here.
[39:09] So half of all the data is noise already. Right. And then whichever register you pick, well, that doesn’t matter either in the code generator. And honestly, you could change your mind at any point in time. So teasing the truth out of that noise is a lot harder than if you just have a program where the variable is called I and whatever. And by the way, that you can relate to the written instruction that the user just gave you.
[39:34] I mean, keep in mind that, like, AI are, they’re just emulators of humans in a sense. Right? I mean, it’s like neural networks. Right. There’s a reason we have programming languages because we’re terrible at writing machine code straight off out of our head. Right? AI is not that different from us, so the same would probably be true there.
Ryan:
[39:56] When you look back on working on C and Typescript and these language projects, they were long journeys and I think, yeah, one thing people might want to know is what did you Learn through those journeys that if you knew at the beginning of when you embarked on working on them, you might have been better off.
Anders:
[40:19] Gosh, well, each journey is different. I mean like the first project I worked on, Turbo Pascal, I think
Ryan:
[40:30] that
Anders:
[40:30] project started back in the old days when it was 8bit micros and 64k of memory and one person could do everything themselves and have ultimate control of everything. And so I was very much a one man shop. But that quickly was not scalable. Right. And capacities of machines. We went from 64 to 640k and then kaboom, the lid went off. Right. And you could have as much memory as you wanted. And so not one person couldn’t do it.
[40:59] And I had to learn to become a team player. Right. And that, that was a big journey for me. I mean to learn to let go. Right. If you’re a perfectionist, that could be hard, but that’s one thing that I would say I learned there.
Ryan:
[41:14] Well, another way to word this question is, you know, what’s the most common mistake that you see people make when they embark on building a programming language?
Anders:
[41:24] Well, I think people tend to over index on one idea that they have that they think, oh, wouldn’t it be cool if my language could do blah. And then they under index on all of the mundane stuff that every programming language has to do and then it ends up doing that one thing they love, maybe better, but then it does everything else not as good. And the net is a detractor. Right. And so it’s so hard to convey how many things you have to do that really doesn’t have anything to do with the problem you’re trying to solve per se.
[42:03] When you’re implementing programming languages, when you
Ryan:
[42:06] were working on C, do you keep tabs on the other languages and what they’re doing better, what you could do better with C?
Anders:
[42:15] Yeah, no, you got to keep yourself informed because like I said, we all stand on the shoulders of giants. No programming language was ever created in perfect isolation. Everyone learns from everyone and then someone comes up with a good idea and then you see it adopted elsewhere. We’ve adopted many ideas from functional programming in C, for example. Then other languages have adopted some of the good ideas we had in C, like Async now is in JavaScript and in some of the other programming languages out there.
[42:46] And that was pioneered in C. You know, it’s, it’s, we all learn from each other and that’s how the industry moves forward. Really.
42:57 — Hands on engineering vs delegation
Ryan:
[42:57] You mentioned the, I guess, learning to let go. I think that’s something that a lot of people, as their career advances, they start with, you know, individual contributor work and then later they start delegating things. How did you learn that? Or what was the. Is there like a, maybe a story or particular project where you let go and you develop that skill?
Anders:
[43:21] Well, it’s almost like I got a counter story to the letting go there because in the C Sharp project, my main function was not implementing the C compiler, it was being the language designer and writing the spec and designing all the new language features. Before that, when I, when I had worked on Turbo Pascal, I was, I was doing a bunch of active coding, you know, on, on the thing itself, right? But then I sort of let go of that, but I let go of it too much and I sort of drifted up into the stratosphere and became more of an architecture astronaut, do you know what I mean?
[43:59] And I wasn’t getting my hands dirty. I was writing stuff in the framework and in the libraries, but it wasn’t, it didn’t quite. These are not like the deep, really super hard problems to solve. And I didn’t really know it at the time, but I was gradually getting less happy with the work that I was doing. I still enjoyed, but there was something missing. And so when this typescript opportunity came along, I decided to jump in and actually actively participating writing compiler.
[44:30] And it brought so much happiness to my life. I finally realized I’m just a happy coder. I mean, I like the spec stuff too, but coding is like, man, that’s what gets me up in the morning, make coffee and write some code. You know, that’s when I’m in my happy space.
Ryan:
[44:48] You know, when people are at these really, really high levels, they kind of have this expectation of a certain level of impact. And so how do you continue to write code as such a high level engineer?
Anders:
[45:02] Well, the specific code I’m writing isn’t necessarily having all that impact, but it’s the fact that I also do the architectural guidance as part of a group of people in a project, there’s plenty of work for everyone to go around, but you stay involved in a corner of the project because then you see what happens in the code. When you’re checking in your code, you go, what was, what was that over there?
[45:31] Let me just, what’s happening over here? Or you realize, oh, we need to refactor this. This is not feeling right anymore. But if you let go of that, you can’t really talk about the thing that people use day to day. You can talk about the Syntax of the thing that people use day to day, but you can’t talk about that thing. So both are important, I think, and I’m happy that I get to do both.
Ryan:
[45:57] Now, I know a lot of companies have this idea of engineering archetypes or the way that high level engineers get some work done. And you mentioned architect, for instance. A lot of companies have different words for architect. I’m not sure if you’re saying it’s just your working style or are you saying that all high level engineers should be hands on at some level?
Anders:
[46:22] No, I’m not saying that because I don’t think it’s like I made a conscious choice to remain an independent contributor as opposed to become a manager. I mean, I have plenty of opportunities, but that is not where I do my best work. Right. So I think you have to decide for yourself what is it that motivates you, makes you happy, keeps you doing this for a lifetime. Do you know what I mean? And you only get one run at it in life here.
[46:54] And if you’re going to do your best work, do the thing that makes you the most happy. I think that’s what I learned along the way, that coding is part of that, a big part of that.
Ryan:
[47:10] So then when you were working on C, but before Typescript, how did you know something was missing?
Anders:
[47:16] I just knew something. I don’t know how. I mean, I just wasn’t feeling as fulfilled with only doing the design part. Right. I missed the coding and whenever I had a chance to write a little bit of code, I would feel a lot happier. And I go, that’s kind of interesting. Do you know what I mean? But now I got to go write some more specs.
Ryan:
[47:41] So then was Typescript something you kind of went towards because you wanted to write more code?
Anders:
[47:46] Well, I went towards it for many reasons. I mean, it wasn’t specifically that to begin with. I just found the problem fascinating. Right? I mean, because the way TypeScript came about was actually indirectly through C. Because the Outlook. com team, I think it was, approached the C group and asked whether we would pretty please productize something called Script Sharp. Script Sharp was this thing that took C and transpiled it into JavaScript so you could run it in a browser.
[48:19] I’m like, what? Why would you want to do that? Why don’t you just write the job? Well, because that way we can get great tooling, then we can use Visual Studio and we can have projects and we can have type checking and we can have code refactoring and navigation and we can write interfaces and people can understand how this all works. And I’m like, wow, is JavaScript really that busted? And you’re saying, like, the way you want to fix that problem is by abandoning JavaScript, treating it as an instruction language.
[48:51] Right. And then having a code generator targeted. I’m like, couldn’t we fix JavaScript? Wouldn’t that be better? Do you know what I mean? And that’s how TypeScript kind of got off the ground, Right? It was like, gosh, there’s something here that’s really broken that needs to be fixed. Right. When it comes to JavaScript tooling, and that’s what we set out to do.
49:14 — Why fast tooling matters more now
Ryan:
[49:14] One thing I thought would be interesting is in one of the talks that you gave, you said that you believe that the speed of your tooling is more important now because of AI, And I want to hear thoughts on why is that the case.
Anders:
[49:30] Well, more and more, our workflows now are dominated by agents that are, like, running away in the background. I mean, like, writing code for you. And they make mistakes just like we do. But you can have as many of them as you want. So there are like, many, many more little workers in the ecosystem writing much more code. Right. And that whole workflow is like, LLMs already have performance challenging.
[50:00] And if you add, like, if you’re writing code in a big project and you have to type, check it, and it takes two minutes every time the LLM writes something. Do you know what I mean? That’s horrible. Right? So making that go faster is a big benefit.
Ryan:
[50:14] Yeah, absolutely. I guess. Because it’s hammering away.
Anders:
[50:17] Yeah, Because, I mean, well, we all know LLMs, they like to use GREP and whatever. Right? But then they’re also smart enough now to realize that if you’re trying to change this property called version, and like every other object has a version property, you can’t just grep for version and then go rename it to something else because, like, you’re breaking all these other interfaces that have a version in them, right?
[50:45] So you got to do semantic search, and the only thing that can do semantic search is a compiler. And so you got to use the compiler through, typically through lsp, through language Services, or through our command line tool. That would give you the equivalent. Right. And so more and more AI is doing that. And that means, you know, compilers run at. You may not even see that they’re running, but they’re running and they’re doing work on your behalf.
[51:15] Yeah.
51:16 — AI software engineering predictions
Ryan:
[51:16] When you talk about AI, it’s very realistic and grounded in the software engineering. And so I thought it might be interesting to run some common AI takes that I hear from the Internet and get your sense of how accurate is this? What are your thoughts on when or if it’ll be true? Okay, so the first one that I’ve heard this was more common at the end of last year, is that AI is going to write 90 plus percent of the code within a year.
[51:49] Curious what you think on that.
Anders:
[51:51] Well, for certain classes of apps that might be like all of I coded apps are writing 100% of the code. Right. And there’s an awful lot of that being written. Are they going to write 90% of the high quality code on the Internet? I don’t know about that. So the thing is like 90% of what the volume of written code is just going like that right now. Right. Because AI writes so much code. So in a sense that’s a self fulfilling prophecy.
[52:22] Right. But when it comes to the super high quality code that no one has ever written before, it’s not clear to me that AI is going to write 90% of that.
Ryan:
[52:35] So when you think about cases that AI is not writing all the code, maybe some examples of the super high quality stuff, what is that?
Anders:
[52:44] Well, I mean it’s algorithms that no one has ever seen before, for example, or particular solutions. Like, I mean, I know that AI could not write our compiler, the Typescript compiler. It just can’t. I mean we’ve tried it can’t do it. And I’m not asking it to either. I mean I’m not expecting it to either. But our compiler is also not a typical piece of code. That’s why it’s bad at writing it, because it’s seen none of it in the training set.
[53:16] Well, I’ve seen some compilers, but not like this one, not with these concepts, not with done the way that we’re doing it. Right. And so it’s just not a good fit there. AI, we can’t forget that AI is at heart a big stochastic machine that has memorized the entire Internet. Right. And has an ability to extrapolate somewhat over what it’s memorized. Right. But if it hasn’t seen it before, it’s not necessarily going to be all that good at doing it.
[53:49] It’s getting better. I mean, I’m not saying it’s not impressive, it’s wildly impressive what it can do, but I just think there’s a long way still to it’s doing all of it. And I don’t know that we ever get there. I hope we don’t. Because then what’s the point of humans anymore then? I mean, it’s.
Ryan:
[54:09] What I see this take often too is you won’t need to use an IDE within the year or you don’t need to read the code anymore.
Anders:
[54:19] Well, good luck to you. I mean, if you’re going to hand AI the keys, I mean, then all bets are off, right? I mean, the minute AI you can’t convince AI to fix this issue or this new feature that you want built, what are you going to do? I mean, if you don’t understand what’s below? Right. That’s one problem. The other problem is, let’s say a user comes to you and goes, your app just stole my bank account.
[54:46] Well, it’s going to sue you. They’re going to sue you. Not the AI. I mean, it’s like at the end of the day, someone has to take responsibility for what AI is doing. And if you’re giving it the keys, well, it’s on you. But I don’t know, I personally would not feel comfortable. I wouldn’t be able to go to sleep at night, I mean, if I didn’t understand what it is that I am vouching for.
Ryan:
[55:13] Why is there such a big difference between this opinion and what I see from maybe people who work at Anthropic?
Anders:
[55:22] Well, the difference is, all I’m saying here is not that AI can’t do amazing things. It does, it can. It does that every day. But people love these, like, take it all the way to 100%. Right. And that’s where I get off the bus a little bit. Right. I think, oh, yeah, okay, fine, we can get higher and higher percentage. But there still has to be someone understanding what’s going on and how it’s relevant to our business problem and how it relates to what our organization is doing.
[55:53] And like, I mean, there’s so many other things that have to be connected that it’s. I think it’s wrong to just view it as AI did it all and we were completely unnecessary, you know?
Ryan:
[56:04] Yeah. The next one I was going to ask you was, you know, three years from now, will AI replace junior software engineers or what junior software engineers do today?
Anders:
[56:13] Well, if it does, then how do we ever get senior software engineers? Right? I mean, it’s just like, I don’t think so. Well, I’m not. Unless you also believe that you will be able to do your business three years later than that without any senior software engineers.
Ryan:
[56:30] Right.
Anders:
[56:30] Because where are they going to come from you got to train them, I mean. But to me, I think maybe one thing that to some extent has happened is that for certain classes of programmers, the pyramid has narrowed at the bottom. There are fewer people coming in, and we are wanting them to advance higher up faster so that they can get to this more supervisory role. I think the craft of being a software engineer is definitely changing from your typing in lines of code to you’re having agents type in lines of code and you are reviewing the work of the agents.
[57:14] So you do more reviewing, less typing. Some people love that and really are fantastic at that workflow. But it’s a change in nature of what the job looks like as a programmer and this tool that you now have in a toolbox is having that impact. But it is but a tool and there are still programmers involved in the process that I firmly believe.
Ryan:
[57:42] It sounds like you enjoy typing out the code. Would you be less happy if five years from now, for 40, 50 years I have enjoyed typing out code?
Anders:
[57:48] I’m actually. And so I will continue to type certain parts of the code, but there are other parts of the code that I don’t particularly care to type. I don’t care to type in tests and follow all the rigor of the particular testing framework. Heck no. If I can farm that out to AI happy me, I do think reviewing has always been harder for me. It’s harder for me to spend time on reviewing other people’s code than it is writing the code.
[58:24] But I also think that over time we can make that process of reviewing code much more ergonomic than it is today. Right. I mean, often today you just get, here’s like a list of the files that were changed and here are the deltas. You figure it out. Right? I mean, AI could help us more there by explaining what the changes are and whatever. And so I think we’re going to get better at this. It’s going to get more interesting, but it will change the nature of, of the craft.
58:52 — The most technically challenging work
Ryan:
[58:52] You said that you’ve been writing code for 40, maybe 50 years. What is the hardest piece of code you’ve ever written? Or what’s the most technically challenging thing you’ve ever done?
Anders:
[59:06] There are so many things that in their time were challenging. I mean, this last project we worked on, we knew that the easy part was getting the native code that’s just like just move it to this other language. But then taming this beast called shared memory concurrency and getting the compiler to use as many CPUs as there are available on your box that is not a simple problem to solve in a compiler because we’re all taught to write sequential stuff, right?
[59:48] I mean, first you do this, then you this. But how do you do all of this at the same time and then share the data structures afterwards without anyone like accidentally modifying the other guy’s data structure? And you know, how do you, in the cases where you have to do that, how do you then synchronize it and avoid deadlocks and race conditions and whatever, Right? This, it was tricky. There were some good technical problems that we licked that I think we can be proud of, you know.
Ryan:
[01:00:13] But what about when hardware was more constrained earlier in your career? Is there any wacky thing you had to do to kind of, you know, make it work?
Anders:
[01:00:23] Oh, totally. I mean, when I started, it was a. Like being a programmer was a very, very different thing, right. I mean, I started out with, with 8 bit micros that had Microsoft Basic in ROM, right? And then the BASIC interpreter and you could buy these books and type in these Star wars games or whatever. They were all text, you know, there’s just scrolling and telling you there’s Klingons over in that quadrant, you know, and K4, you got whatever, right.
[01:00:55] But I got fascinated with understanding how it was all put together and quickly learned how to write assembly code. And Turbo Pascal, the first product I worked on was all written in Z80 assembly code. The compiler, the editor, the runtime library, everything was assembly and writing structured. A compiler in assembly code is like that. A lot of fiddling. And you were counting like, okay, I think we need to squeeze this into this EEPROM.
[01:01:30] And then there’s only 12k and I’m 20 bytes over budget here. Oh, but I can make this jump, this long jump instead. I could jump to this short jump and then jumps to that jump and then I could save one. That’s one bite saved. Okay. You know, moving right along and you would just like sitting there fiddling, you know, it was a craft. It was like woodworking almost. I mean, it was just so different from what we do now, right?
[01:01:57] Everything is now it’s bottomless pits of capacity and bottomless pits of expectation from users.
01:02:04 — Top book recommendation
Ryan:
[01:02:04] Right. Is there a top technical book recommendation you have for software engineers?
Anders:
[01:02:09] I usually recommend the same, but the one book that was like the IT book for me when I was younger, and it’s called Algorithms plus Data Structures Equals Programs by Niklaus Wirth, the inventor of Pascal and then later Modular and Oberon and whatever. And it’s a book that is light on math and Symbolism and rich in instructive examples and good explanations about how data structures work. I mean, that’s how I learned about hash tables, right?
[01:02:43] I mean, like, when you’re self taught, you don’t know about hash tables, you sort of know about linked lists, right? And fine. So in the original version of Turbo Pascal, all the symbol tables were just, well, they were just linked lists, you know, or whatever. And then of course, as you had many local variables, well, you’re going exponential in search time. And then I read about these hash tables and like, wow, what you mean I can just do this?
[01:03:11] And then it’s basically like linear lookup time and implemented and the compile went twice as fast. Right? Like, holy cow, that was useful reading. Do you know what I mean? So I was always like the engineer, I mean, understanding how to do error recovery. He explains that in how you construct a simple compiler. And then like, you know, and it was, for me, a great book. And now it’s actually like, I mean, it’s just a big PDF, you can download it out there.
[01:03:46] It’s out of print since 40, 30 years. Yeah.
01:03:50 — Advice for his younger self
Ryan:
[01:03:50] Last question for you is, with all the experience that you have now, if you go back to yourself when you just entered the industry and give yourself some advice, what would you say?
Anders:
[01:04:01] Well, a couple of things. Maybe like we talked about being a team player, you know, I would have probably tried to educate myself a bit more about that to begin with. I think also one thing in retrospect is like, don’t let people tell you that it can’t be done. When they tell you it can’t be done, it’s because they can’t do it. That doesn’t mean that you couldn’t possibly do it. Do you know what I mean?
[01:04:29] So, so don’t let that discourage you.
Ryan:
[01:04:31] Is there a project where you. Someone said you couldn’t do it and then you did it and that’s how you.
Anders:
[01:04:38] Well, I think the first thing I worked on, like Turbo Pascal, people were telling me, whenever we told them, here’s what we have, they said, that can’t be done. That’s like, nah, you guys are beautiful. That’s like not possible, you know? Well, it was and I didn’t know that it wasn’t possible.
Ryan:
[01:04:55] Right, awesome. Well, thank you for your time. I really appreciate it. Anders.
Anders:
[01:04:58] You’re welcome. No, this is a lot of fun.










