Programming languages can be designed with different memory management approaches, where automatic garbage collection (like in OCaml) provides easier memory handling but introduces runtime overhead, while manual memory management (like in Rust) offers more control but requires significant programmer discipline. Formal verification uses mathematical reasoning to prove program correctness for all possible inputs, addressing the fundamental limitation that testing can only show the presence of bugs, not their complete absence.
Deep Dive
Prerequisite Knowledge
- No data available.
Where to go next
- No data available.
Deep Dive
Creator of OCaml: Functional Programming, Formal Verification, Programming Languages | Xavier Leroy
Added:Testing can only show the presence of bugs, but not their complete absence.
>> This is the creator of the OCaml programming language, and I asked him all about programming language design and formal verification.
>> Oh my god.
>> [laughter] >> Uh yeah, I'm not a big fan of JavaScript.
And Rust is the finest language for manual memory management. Manual memory management is not always faster.
Maybe this will be the the decade of formal verification of software.
>> If you took LLM-generated code and turned it up, what languages would become more popular? What languages might fade away?
>> Woof.
Uh >> Here's the full episode.
What sets OCaml apart from other programming languages?
>> It it is a fine functional language.
Okay, you can like functions by case over inductive types and recursion and combine them with combinators and then higher-order functions and everything. So so it's really a a a fine functional language, but it's also a fairly decent systems programming language.
And um so it has fully imperative power. It has lots of interesting control structures, um exceptions, threads, handlers for user-defined effects, which we added recently.
Um and it has a very predictable cost model execution model. So so when you write your code, you have a pretty good idea what what will take time and what will be fast and what will be slow. And that that's not the case for all functional languages.
Some are pretty unpredictable. And and then the implementation is also pretty performant. Okay, so there's there's a fairly decent compiler, not the best in in its class, but the code is pretty efficient. There's a very good allocator and garbage collector with low latency, so you don't have much pauses.
You don't have long long pauses and that that's quite important when you do things like network programming.
And and so and so you can write systems applications in in in mostly functional style and and with all the benefits of functional programming.
And and so initially OCaml wasn't wasn't designed for those kind of applications, okay? It was more for things like theorem proving or implementing domain-specific languages.
And then we got some of the first users who were from the systems community, in particular the Ensemble project in the late '90s at Cornell University. So so it was a network stack for a network protocol stack for reliable multicast and those kind of, you know, collaborative distributed applications like collaborative editing or multiplayer video games.
And and their first code was in C, of course.
They were systems people, right? And and it worked, but it was unmaintainable and they couldn't extend it anymore. And someone had the idea to try OCaml and and so first the code became a lot nicer and easier to to to evolve and the performance was about as good as the C code. And in particular, they they had this uh brilliant trick of running the garbage collector while packets are in flight, okay? Well, once you've sent a packet, you're you're idle for a few microseconds and so you can run some GC. It costs nothing.
And so they were very happy with that and and and then there were some other projects like this using OCaml for systems applications like the Mirage Mirage uh And and and yeah, and and and another benefit or consequence of this uh Ensemble project is that uh one of the PhD students working on that was Yaron Minsky, who then went to Jane Street and and implemented their their trading infrastructure in OCaml.
Uh so they are still today one of our big users.
>> [snorts] >> And and again, it's well, they do automatic trading, so it must be fast and reliable and and no long pauses, but they also want the elegance of functional programming.
And they want non- non-programmers to be able to read and and their code like financial engineers or quantitative analysts.
And and so yeah, so OCaml is a fairly good match for those kind of applications.
>> I thought it might be interesting to ground some of the conversation here by making comparisons across programming languages, maybe ones that people know more.
When you think about Rust versus OCaml, what are the big differences and the pros and cons of the various design decisions in those languages?
>> The the big dividing line is between Rust and OCaml is uh well, OCaml has automatic memory management, garbage collection.
And Rust is uh is definitely uh a language for manual memory management.
Uh it's a it's it's the finest language for that I know for uh manual memory management, okay? It means manages to to make it uh mostly safe uh with with the discipline of uh borrowing, etc. And uh and and tracking ownership and so on. So it's in infinitely uh uh safer than C or C++, but it's still uh a language where you uh allocate and free memory uh yourself.
And on the one hand, it gives more control over what the program is doing.
On the other hand, it's still a big responsibility. It's significantly harder to write programs when you have to to manage your memory, even with the help of Rust types.
So, so yeah, so for me that that's kind of the main dividing line.
Otherwise, Rust has Well, Rust has many of the high-level features of functional languages, okay?
And in particular in in data structures and ability to do pattern matching and so on. So, it's a very interesting design because they really managed to some kind of fusion between you know, C or C++ style low-level programming and and some of the high-level facilities of functional programming.
But still, that that divide, garbage collection versus manual memory management, remains.
>> So, it sounds like this is a performance trade-off where you give more to the programmer in exchange for higher performance.
>> That's mostly true. That said, manual memory management is not always faster.
Or or or you need to be a very good programmer so that it's always faster.
There's been some some some mostly C++ code, for instance, that that does a lot of copying of objects just because you know, you're you're not quite sure you're the only owner. So, so you make a copy and now you're the only owner. But the copying is is quite costly in time and in and in memory bloat.
So, and and for those kind of applications, a garbage collected language is better.
And likewise with with GC, you can work with shared sharing in data structures, okay? And it's perfectly safe.
Um uh while um uh sharing is kind of limited with uh Rust's uh ownership discipline. Uh there there are more constraints. And so you may end up unsharing and so using more memory.
>> It is surprising to me that um that manual memory management would in many cases be more performant than automatic because for instance in in other patterns in computer science, like let's say letting the compiler optimize things for you instead of optimizing things yourself, I would have thought that, you know, letting some system manage memory for you rather than manually mem- managing it would also be better. So, why is there a difference there?
>> Well, because garbage collection takes place at run time. So, so we need from time to time the the program is no longer computing, executing what what you wrote. It is actually uh uh scanning memory, trying to find uh memory that is no longer used. So, [snorts] so uh there's there is uh a run time overhead.
And it can be uh depending on applications 10%, 20%, maybe sometimes 30%. Um but again uh that that doesn't mean the whole program is 30% uh slower than if uh you had written it with manual memory management because there may have been uh other costs as you said uh uh of of of manual memory management. But yes, um there's Uh um well, there's been a lot of research on on trying to do um more, I'd say, compile time automatic memory management.
And you can do that to some extent, but it it's for for for some some programming styles where it's easy to track the lifetime of of objects and and and data blocks.
But in general, you still have quite a bit of work to do at runtime.
>> I think a lot of people for garbage collection, they might think of it as a binary thing. It's either you have it or you don't.
But I wonder in OCaml, is there some way to like turn down the memory management and do some manual, so kind of like a mixture to have the benefits of both?
>> So that's one of the things that the Jane Street people are looking at. So they have their OCaml variant, Oxidized OCaml, which is kind of OCaml with some inspiration from Rust. So it's still very very experimental, but yeah, they've been playing with things like stack allocation of some data structures so that automatically deallocated when the function returns, which is quite cheap. Yeah, there there are a few things you could try, but but I'm not sure they are going to make such a big difference. I remember doing this with a student some experiments with stack allocation of uh of data structures a long time ago, and you don't win as much as you would think. See, garbage collection or heap allocation is pretty cheap for objects that have a very short lifetime.
Okay, if if they if they die before the next garbage collector, they they they will cost very little in garbage collection time.
Uh but it's more expensive for long-lived data structures, okay, because those will be scanned and uh analyzed uh multiple times.
And stack allocation works for the first kind of objects, things that have short lifetime anyway.
So so you don't you don't win as much as as as you think.
>> Um one of the most popular programming languages JavaScript. Uh curious when you think about the difference between JavaScript and OCaml, what's the main thing that comes to mind?
>> Yeah, I'm not a big fan of JavaScript.
Well, so JavaScript is uh Well, first it's it's very dynamic. So, type checking is entirely dynamic, but it's more than that. I mean, pretty much everything can be redefined at run time, including, I don't know, the semantics of method invocation, for instance. So, so really some some pretty fundamental aspects of the language are very flexible. So, some people say, "Oh, that's great. We can do lots of meta meta programming, etc." And and to me it it also it it's a big weakness. I mean, it it is pro it makes programs that are that can be very fragile and [snorts] also have some security issues. So, so yeah, so JavaScript is the ultimate dynamic language, in my opinion, while OCaml is very static. Static typing, static binding, pretty much everything is fixed at compile time. Okay.
Uh and then Well, I guess it's a kind of a different data data model. Uh JavaScript is a little more object-oriented in in in the way it it presents data. Maybe that's not that important. And and to say one good thing about JavaScript is that it also contains a decent functional language inside. You know, there's there's a little bit of a little core of JavaScript which is basically Lisp and and can be used to do a functional programming if you want.
Um and and actually the the designer of JavaScript, I think, was a former Lisp person. I can't remember his name, but >> Brendan Eich, maybe?
>> Uh yeah, Brendan Eich, yeah.
There there was a little bit of heritage from from Lisp to to JavaScript.
But a very dynamic kind of Lisp.
>> You said you weren't the biggest fan. Is that just because of the dynamics or is there some other aspect?
>> Yeah, mostly the dynamics. I think They really went overboard with that.
This kind of meta meta object protocol where you can really find the semantics of very basic operations like method invocation. The fact that a method can There's a lot of introspection. A method can look at its own call stack, look at its callers, look at the code of their of its callers, which is a security nightmare.
Um All those things I think are completely unnecessary and not conducive to good programs.
Easily abused. Yeah. Easily abused.
>> I think on the topic of functional languages compared to imperative languages, there's this thought that uh functional languages are kind of hard harder to learn or maybe they have more perceived complexity. And actually, I when I my research, there's this popular quote from the designer of Go, Rob Pike.
And he's talking about what they intended to do with code with Go.
And he said, you know, the key point here is the programmers are are Googlers. They're not researchers. You know, they they're young, fresh out of school. They're not capable of understanding a a brilliant language.
And I think, you know, that that thought of a brilliant language is often attributed to functional languages.
What do you think about is a language like OCaml harder for programmers to grasp than imperative languages?
>> I think functional programming is not fundamentally harder, especially if you have a little bit of mathematics background. So, coming back to the quote by by Rob Pike, uh I think it describes very much how they go about hiring at Google. Okay, they they they hire a lot of uh engineers who are fresh out of of college. Some of them have master's degree, but And and then they train them internally. Other other companies I I try to to hire people with more education and perhaps a more diverse backgrounds.
Um and and yeah, so so Jane Street for instance and and some of those use OCaml as a filter on on who who they want to hire.
Yeah, they have fewer applicants, but in general they have more interesting backgrounds. So um And perhaps one last thing I would like to say, Python is 50% functional language.
Okay. Uh a lot of good Python code looks like functional uh code with comprehensions.
So I think uh uh people are already halfway uh through through functional programming uh when when when they are comfortable with Python.
>> Yeah, when I was learning OCaml in college, I think one thing that really stood out to me and I thought was interesting was this concept of type inference where the compiler is kind of uh it knows the types of everything implicitly in the the way that the code is written.
Um can you explain uh type inference and what the advantages are?
>> Well, the the basic idea is that uh you don't have to declare the type of every variable you introduce, every function parameter, every local variable because quite often the type can be deduced from the uses of the variable. Okay? Uh like if you do uh I don't know X equals string length of S, uh then you kind of know that S is a string and X is an integer, right? Because that's what the string length function uh that's the type of string length and it it tells you that.
Um so so that's the basic idea. Uh now the the actual realization is a little more complicated. Basically, you need to collect a number of con- the compiler needs to collect a number of constraints and then try to solve them.
Uh see uh well, if there's no solution, then it's a type error. But, sometimes there are several solutions and you must find good criteria to choose one, otherwise you're I mean, it also needs to be predictable for for programmers.
Um, and often also you can you um you can still put type annotation as a programmer you can still put type annotations if that makes the code clearer.
So, I think the the the main advantage is precisely to have less verbose code, less verbose code. Well, you don't you don't need to put types everywhere, but only where they help uh documentation and and documenting the code and and making the making it easier to read. Okay.
Uh, but quite often you um for for like small local functions, for uh short-lived temporary variables, you you the type is obvious from the context, so let's just omit it.
>> If I'm trying to figure out how this type inference works, the intuitive example you said makes sense. But, uh you mentioned it seems to be some sort of system of equations that you solve or something like that. Can you give a uh concrete example maybe, you know, what does that look like to the compiler?
>> Okay. Well, for a slightly more complex example, say you have um function with two parameters X and Y, and then you do if X equals Y.
So, that tells you that X and Y have the same type, but that still doesn't tell you which type it is, uh assuming a polymorphic uh equality comparison.
So, you've learned something about X and Y, that they have the same type, but you still don't know what the type is.
And later maybe you will learn something about the type of X.
And now you will have determined the type of Y as well.
So, so that's the kind of constraints you you you accumulate and solve, um little bit like, you know, Sudoku or uh those kind of puzzles. And then there's the interesting case where you don't have enough constraints to find a unique type.
So maybe in the end X and Y will be you know they have the same type but it's still unconstrained.
And and then that's where you automatically get polymorphism for free.
Okay, the type checker said, "Okay, those types are unconstrained so it can work for any type."
So my function can take an X of any type and a Y of the same type. Again, any type and it's a polymorphic function.
So there's there's this beautiful I think phenomena phenomenon that that polymorphism can be discovered just by running type inference and noticing that oh there are no constraints so it must be polymorphic.
And and that was a great insight by Robin Milner, the British computer scientist pioneer who invented this ML family of languages and and and this kind of type inference in the 70s.
Polymorphism was was was not very well understood at the time and so the fact that that he could have he could introduce polymorphism so easily in his language just as a consequence of type inference was a beautiful discovery.
>> So for type inference it seems like the benefit is you know the code is going to be a lot more concise because we don't need to write out all the types which seems nice. But what are the tradeoffs of adding type inference to a programming language?
>> Well, as I said error messages can be type error messages can be very confusing because they not always point to the actual source of the type error.
Okay.
The system may have done some some wrong inferences and and and will report though some of those inferences instead of reporting the source the actual source of the type error. So, it's been it's been the subject of much research.
And and there's there's no very well-defined idea of the the source of a type error, basically.
Um so, yeah. So, errors can be an issue.
Some features of type systems are easy to combine with type inference, to handle with type inference, and some are harder.
Uh for instance, when it comes to genericity, so I mentioned the polymorphic parameter uh parametric polymorphism, which which is very well handled, but subtyping, the kind of uh thing you have in object-oriented languages, is actually harder to to combine with with type inference for super technical reasons that I'm not going to to go into.
Um so, so sometimes uh you have to make a choice. Either you have type inference, but it is less powerful, uh or you you have uh full type inference, but more restrictive type system.
Uh And and that that that that choice is part of the language design, actually.
>> You mentioning this uh solver kind of reminds me of the topic of formal verification. Could you explain what formal verification is?
>> Woo.
Well, it's the idea that um um you for for some programs, you want you want strong guarantees that that that the program is correct. Well, and and guarantees that are hard to get just with testing and and reviews, code reviews.
Uh you know, there's uh this famous quote by uh Dijkstra, the the Dutch computer pioneer, uh which is which goes something like uh testing can only show the presence of bugs, but not their complete absence.
Uh because in general, there's an infinite infinitely many inputs to your program, and you cannot test them all.
So, you only test in your sample and then sometimes you have surprises.
So, what if you want to make sure that program is correct for an infinite number of inputs?
And that's where you need to turn to those so-called formal methods. So, you're using mathematical reasoning, you're using the uh uh static analysis algorithms on your on your program to really analyze all possible executions of a piece of code and making sure that it matches a specification.
The specification can be very simple like the code will never crash given well-formed inputs.
So, that that's a fairly simple property, but still extremely useful because code that crashes is always code that can be attacked. It's always is often security hole.
>> [sighs and gasps] >> Um so, for instance, all accesses within array all array accesses are within bounds.
That's a very simple property and it's very hard to to ensure just by a type system or just by testing. So, that's [snorts] where you need some more advanced formal verification.
And then there are there are much more powerful specific much more precise specifications that you may want to check that can be where the program always terminates. It can be the program doesn't [snorts] leak confidential data. It can even be where the program computes this mathematical function >> [snorts] >> uh with with an error floating point error under I don't know, 10 to the minus six. Okay.
Something like that. Something very precise like that.
And so, it's it's been really hot topic in in in in software sciences since the uh since the '70s, I would say. There's lots of techniques.
Some are just fully automatic like static analysis, uh but they're already pretty good at finding bugs and making sure that some bugs like array out of bounds are not there.
And some are a lot more interactive and and require a lot more formal assistance to write specifications and then do can so called program proofs. So proving mathematical statements about the program.
>> I hear about it a lot more now which is lean and these theorem provers.
Um what are those in this context and how how are they used?
>> Uh so yeah so lean is is an example an instance of the so called provers or proof assistants.
Um so originally those were developed to do mathematics on the computer. So not nothing with not formal verification of programs but but they can also be used for formal verification of programs. But the initial motivation was really to do mathematics with the help of the computer.
Um where originally everyone focused on automatic theorem proving. So having the machine find proofs from all by itself.
But that's very very difficult and not necessarily what what mathematicians need.
And so those proof assistants are more like where formal language is like like programming languages but where you can write mathematic definition mathematical definitions mathematical statements and they will help you prove. So so some small proof steps they will do automatically and for others the the user still has to guide the prover through through the major steps.
But the good thing is that the proof is recorded also in a format that the machine can understand and recheck.
So when you complete a proof in lean or Coq, or Isabelle, or one of those tools, and and it is rechecked, and and the computer makes sure that all inferences are justified, that you didn't forget any case, that you uh you didn't use a conclusion as an hypothesis, or where all all kind of problems you can have with a pencil and paper proof.
And so, in the end, you get proofs that are extremely uh reliable, extremely credible.
Um and and it's been so so those tools have been used a little bit uh for well for for for some um uh some big mathematical results, where where the proofs are so big that that that they can't be done just by humans.
They really need uh computer assistance.
Uh I think there's a recent example with a weak uh Goldbach conjecture. Uh so, part of the proof involved checking a whole lot of inequality, maybe a thousand inequalities involving several real variables, and blah blah blah. And so, um computer assistance was really needed uh to make sure that that everything was checked, and and there was no no human mistakes uh left.
And and maybe we'll talk about generative AI later, but there's there's also now a lot of interest in conjunction with generative AI.
Uh AI is pretty good as that coming up with plausible proofs.
Okay, but then they have to be checked by humans.
Unless uh AI writes a proof in one of those formal languages like Lean, in which case it can be checked by a machine, and that's much more much more effective.
Um So, yeah. So, it's it's the idea of of using the machine to help you write proofs and recheck proofs that you've written yourself, or maybe with some help from an AI.
And now those tools can also be used to prove properties about programs.
And so so I I spent uh many [clears throat] years uh uh proving the correctness of a compiler, C compiler, uh using one of those tools, the the Rock uh proof assistant.
Um so so basically um when I'm proving about the compiler, so it takes C code, it produces assembly code, and um proving that the assembly code is faithful to the C code. So so there's no miscompilation. The the compiler didn't introduce a bug in the program that wasn't there originally.
And and it's a fairly big proof because compilers do complicated things about programs, and then you have to define exactly what it means to preserve the semantics of a program. So you have to define the semantics of your programming languages. And and so so it's all a very good use of those uh uh machines uh of those proof assistants. Uh the the same work could be done on paper, but I mean this would be a proof of several thousand pages, and nobody would want to read it.
Nobody would trust it. It's just too big. Uh and and it would be very hard to evolve. Um One good thing about um those um mechanized verifications of of programs is that uh it can also help you evolve the program.
Okay? You can add new features and so on, and and adapt your proofs, and be really sure that you haven't introduced a regression or things like that.
Um so yeah, so it's really uh programming taken to a higher level. Um And and today it's quite expensive. Um it takes a lot more time to to prove a program than to write it in the first place. But maybe this is getting a little better.
Um Yeah, and I should also mention another great uh of certified software is the it's a microkernel, the SEL4 microkernel, uh developed in Australia, and which is used as an hypervisor in in some in some applications.
And so it is uh is really like 8,000 lines of extremely technical C code that that, you know, manipulates uh uh processes and uh capabilities and security tokens and so on. And it's been proved correct. Every line has been proved correct. And that that's a very big achievement.
>> When you mentioned the example of verifying a mathematical proof, that uh makes sense to me. When you talk about proving something about a program, it's a little bit more abstract to me or I'm having some trouble visualizing.
Could you give a concrete example like uh maybe some trivial program that we're trying to prove something about it and how that uh theorem prover would work.
>> Let's say you have a function that takes three numbers, X, Y, Z, and um returns the average of those numbers.
Okay?
Um only yeah, and and maybe you're using a not completely obvious formula like uh T equals X plus Y and then T equals T plus Z and then um T equals T divided by 3 and then return T. Okay? So not that exactly is the formula for the average.
Uh and you want to prove that that function is correct. So so you want to prove that it it returns uh X plus Y plus Z divided by 3. And maybe you will have to make it clear whether you're rounding up or rounding down.
If you're using integers or floating-point numbers, you know, it's not a exact arithmetic, so >> [snorts] >> um So, yeah, you you'll have to to say exactly what you mean by divided by three.
>> [snorts] >> And then, uh if you are in a language like C, you can have arithmetic overflows.
Okay? When you compute X + Y or + Z, um you can overflow the range of representable representable integers, and in C, it's it's a bug. It's an undefined behavior.
So, typically, you will want to put a so-called precondition on your function saying, "Okay, uh if you call me, call me with numbers that are between, I don't know, zero and 1 million for instance, but no bigger than that." And and then, the prover will check that no overflow can occur in this case.
Um okay? And so So, basically, you have the precondition that says, "Okay, these are safety guarantees um that must hold of the parameters, otherwise, anything can happen."
And then, there will be a little bit of kind of symbolic execution of the function body that says, "Okay, when you T equals X + Y, then T plus equals Z, then T {slash} equals three, then in the end, T is X + Y + Z divided by three, provided no overflow occurred."
And then, you put that with a precondition that says, "There cannot be any overflow," and you get your final result.
Okay? So, basically, you're stating a contract for your function, the pre- hypotheses on the arguments, uh guarantees on the results.
And uh and and you want to prove or analyze the function body to show that this contract is respected.
I hope it's a little more concrete.
>> So, it it sounds like a lean will help you basically take in some invariants about a program and kind of propagate them through line by line and uphold them. And so you can say something about >> Yes.
Maybe not Lean by itself. Well, a program prover a program prover will do exactly what you say.
And for Lean to be able to do it, you still need to teach it a little bit about the semantics of your programming language.
Okay, that what does a plus means, what does assignment means, okay? Lean Lean is mathematics. You don't assign in mathematics. You don't say x equals x plus one or or or or you're just comparing x and x plus y and it's always false. There's no assignment in mathematics. There's assignment in many programs. So you need to make it explicit that there are [snorts] actually three different states for the t variable, three different values and and and relate [clears throat] those values to Well, the program defines what those values are and then a prover like Lean can can reason about those three successive values.
Because now you're in you're in mathematics.
And and that that kind of bridge between programs and their mathematical meaning is called semantics. That that the field of semantics of programming languages has been a big topic in in PL research since the the '60s at least.
>> Am I understanding then that like a pure functional programming language, the gap between mathematics and the actual symbols is much smaller than an imperative?
>> Absolutely. Yeah, you're you're absolutely right.
And that's one of the reasons why people who do formal methods don't like assignment, don't like imperative features.
Purely functional style is much closer to mathematical style, so much easier to reason going There can still be few discrepancies between the program and the math. Uh, for instance, functional programs may not terminate.
They may loop forever. Um, mathematics doesn't like that. So, so you need a way to to reason about termination.
Um, and uh and also yeah, sometimes for instance, the the arithmetic you get in the programming language is not uh, integer arithmetic or is not uh, real reals. [clears throat] You know, it's floating point, it's not reals. So, so you still have to uh, account for that gap. Uh, but you're you're absolutely right that the gap is much shorter for functional programming. And and uh in the experience of CompCert, my my verified compiler, I think the the first decision was to write it in a purely functional style so that it would be easier to to reason about it later.
>> You mentioned the the specifications that we could prove, and one of them was proving that the program terminates, but I thought that's a famously difficult or impossible. I forgot exactly that the halting problem, right?
So, how how is that something that you could prove?
>> Okay, so what the um computability theory says is that there is no algorithm that will always that can always say this program terminates or this program doesn't terminate.
Um, so so there will always be some very weird programs for which your your analyzer your your automatic termination analyzer will produce a wrong result or will not terminate itself.
Uh, so it will not work.
Um, uh but still for for many programs, you can succeed. Okay, you can write automatic termination analyzers that will work for a large uh class of programs.
And then the termination analysis, termination proof can also be done by hand by by a mathematician. Okay, so So, perhaps a human can can see through those weird Turing programs that that are hard to prove to terminate and and and recognize the trick.
But, anyway, so yeah, it's a hard problem and all all program verification tasks are are difficult pro problems, okay? Uh They are pretty much all undecidable.
So, you know that there there is no static analyzer that will always find all problem all problems in all programs.
>> [snorts] >> But, still you can try, okay? You can try for specific problems, for specific programs and and get some very useful results out of them out of that.
You only need to be able to do it for the cases that are of interest to you, the programs you really care about.
>> 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. 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. One thing [snorts] I saw when I was researching OCaml is that uh in 2022, OCaml added multicore support. And but from my memory, I remember multi-core processors became standard much earlier than that. And so, I figured there might be some unique engineering challenge in adding that support. So, yeah, what what happened there and what made it difficult?
>> Uh well, there were engineering challenges, that's for sure.
There there were also some language design issues.
So, so but let's talk about the engineering challenges first.
Um so, it's true that that when you have a a language with with a runtime system memory allocator or garbage collector uh well, at least the one of for for OCaml was really designed with sequential executions in mind.
So, if you have if you add a shared memory concurrency, then you need a garbage collector or a memory allocator that that that that can work concurrently. And that's actually quite difficult.
Uh at least if you want them to be fast.
Of course, you you could always, you know, take take take a lock at at every operation in the heap, but then uh you would sequentialize your programs. Basically, they they they would run as slowly as a single processor. So, so that's not interesting. So, yeah, so there were engineering challenges. Um um yeah, I was at least initially quite quite reluctant to uh basically re-implement a complete uh garbage collector and and uh memory allocator or large parts of the runtime system. That's what we did eventually with uh as well, it was done mostly by the team at OCaml Labs at Cambridge University.
>> [snorts] >> Uh but yes, it was a really big rewrite.
Um but then I said there's also a language design issue.
Which is that for for the longest time well uh is now when when you say uh multi-core processors and so on, pretty much everyone and language support for multi-core processors, everyone thinks about language support for shared memory concurrency.
You know, this model where you have several sites of control and they access the same memory and basically the sites communicate by modifying the memory and someone else is going to notice.
You know, it and I've never liked this model of of communication.
I mean, it's a bit like if you want to communicate with your neighbor then then you you you break into their houses and their house and then you move the furniture around and then when they are back they say, "Oh, something something was moved so it's probably Iron who's trying to tell us something."
Maybe you could just meet your neighbors, you know? And and that would be things like message passing which is a completely different form of communication, much higher level.
So, yeah, so for the longest time I was really interested in message passing concurrency.
And there's for instance a functional language called Erlang that was built on around those ideas and that I found quite interesting.
However, I never got to to have a decent language design and everyone was saying, "No, but but it it's it's too costly. It's not effective. There's too much copying of data.
With shared memory you can you can share some kind of huge database in memory. If you don't modify it too much, then basically the sharing is the the concurrency is free.
While with message passing we'll have to exchange a lot of data so to to get the same effect so so you will pay more for it.
Anyway, so so okay, so starting with Java I guess and then C C++ 2011 there was this idea that okay, we we we need to expose shared memory concurrency to the programmers.
But then comes the problem of the memory model, which is that what happens when there's a race, for instance, when when two uh two threads want to access the same uh location, and maybe they want to modify it in different ways.
And so, sometimes parts of the C C++ standard says, "It's undefined behavior.
Anything can happen." But still, you need to give a little more guarantees.
Uh at the other end of the spectrum, there's a so-called uh sequential consistency, which says, "Well, what happens is like an interleaving of reads and writes of your program."
You don't know which interleaving, but there is an interleaving.
But that doesn't work with modern uh processors, multi-core processors.
They reorder memory accesses in in very clever ways to get more performance. And so, viewed from the program, it's very hard to predict what they are actually doing.
And so, you need to give your programmers, when you're designing a language with shared memory concurrency, you need to give your programmers some guarantees about uh the ordering of reads and writes, concurrent reads and writes, while not constraining the hardware too much.
And it's very difficult. So, Java went through like five different iterations of the memory model. Some were too strict, some were too lax, some were kind of in inconsistent. They were were were making predictions, impossible predictions, where where the past depends on the future.
>> [snorts] >> Crazy, really crazy stuff.
Uh then C C++ 11 did a little better, but still extremely complex memory model. And so, when we wanted to add when the especially the OCaml Labs people wanted to add uh shared memory concurrency to OCaml, we had to also agree on a memory model that would be exposed to the programmers.
And and that's also took quite a bit of a design uh quite a bit of time to come up with a good design. Uh And I I think it's it's better and easier to understand and use than the one of Java, but the the OCaml memory model is still quite complicated.
And And sometimes I feel sorry our users are are exposed to that. Okay. Uh Uh So, that that that explains why it took so long.
Solving the engineering challenges, but also having a agreeing on the memory model and what kind of guarantees we're going to give to programmers.
Oh, yeah. I forgot to say one thing, which is that So, C and C++ there's a lot of things you can say, "Oh, it's just undefined behavior or anything can happen."
In type-safe languages like Java and OCaml, you want to give stronger guarantees. Okay. Maybe many things can happen, but your data should should remain well-typed.
Okay. Typically, you don't want to expose an object to another thread before it's been fully initialized, for instance.
Um And And that's that's actually very hard to guarantee in your memory model.
And then you have to implement that memory model, so your compiler also needs to take extra precautions to to to guarantee this. So, yeah, type safety in the presence of shared memory concurrency is is not obvious at all.
And so, that's why it took so long.
>> So, in Python, I know there's the famous GIL or the global interpreter lock. What is that lock protecting? Is it the the cleanup of objects on the heap or is it something else?
>> Among other things, yes. So, yeah, we we had the same thing in OCaml before before multicore OCaml with >> [snorts] >> with Marstin. So, yeah, well, basically, the idea that when when your runtime system is not thread-safe, as we said, you can protect the non-thread safe functions by your lock so that they will never be executed concurrently.
But if you take the lock at every allocation and release it, you take and release the lock for every allocation and it's just too slow anyway.
And so the idea is that you take the lock when you enter Python code, let's say, and you start executing Python code.
But you can still release it when you do input output for instance, when you're going to block for a long time.
Or when you're calling into C code that that that is thread safe and is not going to use your runtime system.
Then you can release the lock and some other Python thread can take it and execute.
So you get a little bit of concurrency.
You can overlap computations in your high-level language with IO or computation is a low-level language in another language.
But you still have mutual exclusion between your between two threads running Python or running OCaml before before multicore OCaml.
So so you get some benefits like concurrent IO, but you don't get any parallelism.
Okay, yeah. You don't get a speed up for computations.
And so so yeah, so we used to have this this this GIL in in in OCaml as well.
And so you can get rid of it, but in general, you need to redesign at least the garbage collector and and memory allocator.
There's probably a few places in the OCaml runtime system that still use locks to to to ensure mutual exclusion like in the IO subsystem.
And and some phases of the garbage collector, I think that there's a phase which is kind of stop the world where you need to make sure that everyone no no no camel code is is running.
So for a short time you need to make sure that everyone is stopped and then do a little bit of work to finish the GC and then you can restart everyone.
Um so yeah, that these are tricky things and I don't know what the Python people are up to with their GIL if if they finally managed to remove it or they're still working on it but I I I've heard they're making progress. So.
>> Yeah, you mentioned Python calling into C and I've seen that pattern before of a higher level language interfacing with a lower level one. How does that binding typically work?
>> Oh, it's another can of worms.
Um Um Well, there are two aspects. There are there are the the control flow and there are the the data.
So the control part is is not that hard. So yes, you need you need a mechanism so that your your Python interpreter or your OCaml compiled code will actually jump to the C function.
Uh so for OCaml basically you you tell your OCaml compiler that this function is not implemented in OCaml, it's actually implemented by a C function and you give its name and then the compiler will emit a call to the C function using the C calling conventions which are not exactly the same as the OCaml calling convention but the compiler knows about that. And so it will call the C function maybe through a little bit of glue code or whatever and then the C function will execute and and return back to the OCaml code.
Um That's relatively easy. Uh now the hard part is uh data uh like function arguments and function results because OCaml and C have different data representations.
Uh for instance, a floating point number in in OCaml is generally boxed, so it's allocated in the heap and handled through a pointer. So, it's more like a double star in in C and it's not a double, which is not allocated.
Just it's in a register.
Um so so typically the C code needs to use a so-called foreign function interface, so some C function and macros provided by OCaml to access the OCaml data, the OCaml arguments, you know, extract the part that it needs, the the numbers, the uh uh yeah, another example is arrays. Um in OCaml when you have a two-dimensional array, it's actually an array of arrays. So, viewed from C, it's an array of pointers to arrays.
While in C, an array of arrays is there's no intermediate pointer, so it's not the same representation. And so, you have to explain to C or give C some functions and macros to to access uh elements in OCaml arrays. Uh it's not exactly the same code that that that that that you would do to access a C array from C.
Okay, so you need accessors, but now if you want to uh if your C code wants to return some complex results like a list, an array, and so on, it needs to allocate it in the OCaml heap. So, it needs to ask the runtime system to do some heap allocation and then fill the uh >> [snorts] >> heap blocks correctly. And then this allocation can can trigger a garbage collection, so the C code that also kind of cooperate with a garbage collection with registration mechanisms, etc., etc. So, so there's quite a bit of work to to be done.
And and uh and then different foreign function interfaces arrange this work differently. So, there's a base FFI for OCaml, basically uh it's a C code that must do all the work.
But but then it can be very fast and quite optimized.
Uh but there are other FFIs like the C types FFI in OCaml where most of these data conversion and and mediating between two data formats is automated.
Uh you start basically with a description of the the the the the C type of the C function and and you can automate some of those conversions. But sometimes it can be tricky it can be expensive. For instance, [snorts] you may end up copying the whole array while your C code only needs to access two or three elements in it.
Um okay. So there's lots of trade-offs.
And quite frankly it it's a dirty part of of programming language implementation. Uh the the OCaml FFI is not that clean, but if you look at the Java FFI for instance, it's also quite complicated. And for Python I've I've never tried. Uh so I I don't know what it looks like.
Uh but yeah, it's a it's a necessity.
Uh but but it can be quite hard because the data models are different between the two languages.
>> So to kind of get the big picture, on the OCaml side, there's an interpreter which is a program running in application space that is interpreting your OCaml code. And then at some point in the OCaml code, it says do some, you know, load this C program.
And the C program is a binary somewhere.
And the OCaml interpreter then starts to load those instructions and execute them.
>> Okay. So actually this is the third aspect that I didn't touch.
So so OCaml well, there's an interpreter mode, but in general we compile. We compile to assembly code and then machine code.
And so so in in in compiled mode, what what you say is how you put together the OCaml code and the C code is done by the the linker, the C linker. So so So basically someone else is doing that for us. And and and it's not that different from linking together two object files produced by C or two object files produced by OCaml.
But you write that for for more interpreted languages, there's also the question of how you load the C code.
Generally you know you use the dynamic loading like interface dlopen for instance in in in Unix.
So and and and then there's a little bit of introspection. So so at at run time the interpreter will query the C libraries and where is the address of a function named foo? And then it will find the address and use that to manufacture a call. So yeah, if you're in an interpreted setting or or bytecode compiled setting like Python, it's there's this additional level of complexity on top of it.
>> I see. I see. Okay, so if I had a mixed OCaml C program to my computer it's just one binary or one one blob.
>> In in in the simplest case, yes.
There are also dynamic loading facilities in OCaml, but I don't want to get into that because I'm a firm believer in static linking. I think programs should be statically linked so that there's no surprise when you run them. Okay, like oh, where is this DLL or DLL not found for instance problems.
But of course you lose a little bit in flexibility.
But yeah, I think the static static linking has a lot to is is actually quite useful in in that it it guarantees a lot of things. It checks a lot of things at link time that you don't have to check again at run time.
>> We mentioned earlier in the conversation talking a little bit about LLM generated code. I thought that might be interesting to cover. Um and in one interview you talked about the danger of almost correct code. So, plausible code but it's it's wrong that an LLM can produce. And what are your thoughts on you know how to address that kind of problem?
>> It's it's it's a tough problem. I mean you um globally I'm a little bit skeptical about generative AI. Oh, of course they they they they can do amazing things that were unthinkable like a few years ago.
But there's also there's always some errors. Okay. It's it's you can't really trust oh what's what's being produced by by generative AI.
And so the the uh in principle humans should be there to check the output and and fix errors or ask the LLM to fix its own errors until the result is actually usable. But of course it's very hard because well there's a slot problem. Okay.
AI's produce so much it's so it's so easy to produce uh to produce large number large quantities of text of code or pictures or whatever that that that in the end there's there's there's no human no no no human time to to check it all.
So, recently I heard a uh well someone working in an AI startup who was enthusiastic about uh AI generated code thing that thanks to Genady AI is a cost of programming is dropping to zero.
But well, the cost of writing code maybe, but what about you know checking it, making sure it is correct, um that it does what we want, that well, that cost is not zero at all.
>> Uh-huh.
>> And and for me every new line of code is a liability.
So you you have to test it, you have to check it, maybe you have to do formal verification. You have to evolve it, maintain it later. So so no, I don't want huge amounts of code, okay?
I want I want 50 lines of code that have been thought that have been polished over the years.
So anyway, I'm not getting that with AI.
And and and I think that's the problem.
And this idea that humans will be there to check the output of Genady AI is just wrong.
No, they they they are not available for that. They There's too much of it and it's and it's [snorts] not it's not pleasant either, okay? I mean, I don't think it's a good way to to to split the work between machines and and humans.
So anyway, so maybe there will be some social solution like big >> [snorts] >> no to AI slop movements. So we we we're trying to see that in some open source projects that that refuse AI generated contributions because there's just too many.
>> [snorts] >> I know that well for for for OCaml and especially for Coq Certified have have received some uh uh issues, a lot of issues that were obviously generated by AI. And there was maybe one good issue among 10 reports, okay? And and and each report was several page long and it's, you know, very detailed explanations, and repro case that in the end doesn't repro anything or repro reproduces something else. And but but it takes time to to go through all those things, and and maybe at some point I will say no to to AI generated contributions.
Okay. But maybe there's also a bit of a technical solution, which is, as as we said earlier, to have AI produce proofs, so evidence that its creation is correct. So, as I said, this is starting to work for mathematical proofs. Some generally the AIs are able to produce proofs both in English and in the formal language of the Lean prover, for instance. And so, you can get a Lean to recheck the proof and get some confidence. You still need to be very careful about the statement, because sometimes AIs will change the statement or the definitions to make the proof easier.
That happens.
And also, you you should be careful about so-called self-formalizations, where the the AI also comes up with some definitions and some statements by parsing a PDF file or whatever, and and sometimes it introduces errors at that point.
So, anyway, there's still need need for human review, but on smaller quantities of of text and and mathematical text.
And maybe one day it will also work for program proof. So, when an AI generates a program, it might it be able to generate some Lean proof or whatever, that that the program satisfies some specification.
Um So, I I think it is possible.
Um but now the question will be where does the specification come from?
It's always been a big issue for formal methods.
It's not just that verification is hard, but agreeing on the spec can be can be difficult, too.
And well, mathematicians have a lot of experience, you know, in in stating finding a definition that they find interesting and stating theorems that that that that they believe should be true or or or that that will um mean something.
Computer programmers are less good with that. And it's fairly easy to come up with specifications that are inconsistent for instance or impossible.
Uh so, remember this this average function where there was a a precondition of the three numbers three arguments saying they must not be too big.
But say maybe you you can end up with a precondition that that just cannot be satisfied.
And and and and at this point, the body of the function will always be verified, okay?
Even if it's completely wrong because because the assumption says basically this function cannot be called.
Um and and so, you get a false sense of confidence.
Okay, you verified something, but but it's actually unusable.
And and and that that's a fairly delicate point where I'm not sure LLMs are going to or AI is going to help much.
Uh but but it's a problem with formal methods in general. And and some possibilities include uh the ability to test specifications for instance.
Um so, instead of using your test suite to to to see if your code works out, you can also use it to see if your spec um um it checks out. Um those kind of things, but um yeah, we we're kind of moving some of the difficulties from the programming phase to the uh specification phase, but we still have some problems.
Anyway, so that might be a way to to deal with the um uh AI-generated code and and and develop some confidence in it.
>> You know, LLM-generated code is becoming extremely popular, and I think there's a lot of potential downstream consequences on this on the programming language uh landscape.
And I thought it might be interesting to hear your thoughts on speculating. Like, imagine 10 years from now, if you took LLM-generated code and turned it up, how might you think that the programming language landscape might change?
>> Yeah, a couple of years ago uh someone asked me about that, and and there was there was a a concern that the training data would be um there wouldn't be enough training data in OCaml uh for for an LLM to really learn how to program in OCaml.
And it's true that there's less OCaml code in the wild than uh JavaScript code, for instance.
Uh but apparently um uh contemporary LLMs do do do well with with uh the amount of uh of OCaml code uh they have.
Uh maybe because there's enough, maybe because learning has become a little more efficient, maybe because uh well, there's there's there's less OCaml code than JavaScript code, but maybe the OCaml code is better quality average on an average. I don't know. Anyway, uh maybe LLMs are getting better also to to transfer knowledge from that they've learned from one language to another.
That that could be. Um I have no idea how those things work.
But yeah, so so the latest feedback I've got about LLMs and well, yeah, generative AI and OCaml is that the the OCaml code generated is is quite decent and quite similar in quality to to more popular languages.
And one thing that seems to help the generative AI is a type system. So the fact that there's some static checking just of the types uh uh it's already uh effective in, you know, the uh avoiding some some errors and maybe uh encouraging the LLM to like like declare types uh first. Um so so give give some type structure to the program.
All right.
Um And now from 10 years from now, it's it's it's difficult to guess. So, will it be the more the more popular languages of today that will be even more popular because of generative AI?
Will it be the safer languages of today that will be more popular with AI because uh well, because there's fewer errors in the end?
Um I'm hoping it will be the the safer languages, but uh I really don't know.
>> I've seen in the industry, there's a few cases where because it's so easy to generate code, uh massive rewrites are something that would have been very infeasible in the past are very realizable now. So, if there's an existing project where they chose a programming language for whatever reason in the past, they could translate the entire thing into another language with reasonable confidence. Given that kind of environment, which programming languages would you expect more people would switch to because they they want to switch to it but they weren't able to in the past but now it's cheaper so they can.
>> Well, so today it seems I've heard mostly about C and C++ to Rust translations hoping that the generated Rust code will be safer.
He said I've seen at least one project when the generated Rust code is entirely in unsafe blocks. So so it's really kind of line by line translation of the C code, you know, it's but well, but maybe it can still be used as a starting point for making it safer later.
So yeah, I would say today I can imagine significant efforts being being done with Rust as the as a target language.
In the functional world, I'm not quite sure. Well, maybe or well >> [snorts] >> maybe functional language to one of those proof assistants like like Lean or Coq because they they also have programming languages functional programming languages in them much more restricted but much more amenable to proofs. So maybe for a few projects that that could be interesting as again as a first step towards a formal proof as we as we said earlier.
>> When you compare industry versus academia, today where would you say most of the innovation in programming languages comes from? And also has that changed over time?
>> Okay, well, I think the most of the innovations have come from industry lately.
And that wasn't the case in the early days of computer science.
If you think of I mean, the the totally innovative languages like like Algol, Lisp, uh um Prolog, uh Smalltalk were were developed in mostly academic settings. Well, Smalltalk was Xerox PARC, which was an industrial research lab, but very very far away from uh industrial customers.
Uh and then there were, you know, much more uh practical languages and ugly uh uglier languages developed typically at IBM like Fortran, COBOL, PL/I, etc. Um and then um so so really the idea that the the the nice ideas come from academia and and mature there. Uh And then uh well, the nice ideas from academia started to to be transferred by industry much much more quickly. I'm thinking of well, C and especially C++ and then Java, which really uh took uh ideas like object-orientation and uh well, garbage collection, automatic memory management uh in in um in industry.
All right. Before Java, it was just, you know, uh crazy academics in the ivory tower that were using garbage collected languages, right? It was completely impossible to have that in enterprise compu- computing. And Java came and 2 years later everyone was doing garbage collection and being very happy about it.
>> [snorts] >> Uh and then there were well, Java also popularized type safety um bytecode verification. Well, some some pretty advanced techniques of the '90s.
And if you look at further developments, uh I don't know, Swift for instance popularized the idea of algebraic data types and pattern matching. Uh and then Rust uh and uh Uh, well, Rust is even more spectacular, I would say, because uh, well, algebraic data types, garbage collections, etc., those were already present in in academic languages like, well, Camel, for instance. But, uh, Rust really took very recent research results of the 2000s and safe low-level programming that were basically never implemented in any language, and managed to do a a consistent whole, uh, from that.
And so, I'm I'm really admiring it.
And I have the impression that well, uh, uh, I would have loved if if Rust came out of academia, uh, but I'm not sure it would have been possible, because it's also a huge effort, and you really need uh, the backing of of a big, uh, company.
But, still, I'm not I'm not sad because, uh, I think it's also a very good sign that industry is interested in new programming languages.
You know, at at some point, in in the '90s, well, pretty much when I was hired uh, at INRIA on a research position, uh, uh, when I was hired as someone who had developed uh, first versions of OCaml, well, predecessor of OCaml, and who was working on type systems for programming languages, and so on.
Uh, but then some people told me, but there's no future in programming language research, right? Industry has decided it will be C++ forever.
So, deal with it. Uh, maybe maybe you could do software engineering, and not not not PL research.
Uh, and then Java came a few years later, and and showing that no, uh, industry hasn't [clears throat] decided on a functional on a on a particular programming language. Industry is still in interested in new programming languages. Industry still thinks that a new programming language can be part of the solution to to software problems.
And and I find it extremely encouraging.
We are not stuck with with bad languages from the past. Well, there's a lot of legacy code, of course, but but they're still uh um real interest for for for better languages, and I think this will continue, and I think it's good for for the computing field.
>> In 2018, there was a interview that you did, and they asked you what are the most interesting and important problems to focus on in the coming years.
And you called out the difficulty of programming, you know, GPUs, cuz they were using dialects of C, shoddy tools, and also the challenges in verifying machine learned code, basically. Um and that sounds pretty relevant today, but what would you say your answer is today?
>> So, yeah, I think well, for for the um um the question of how we program massively parallel hardware, I think we we've made a little bit of progress recently with things like the uh MLIR initiative um on the on LLVM, or some domain-specific languages uh like Halide, which are pretty good. You know, those tensor uh domain-specific languages for tensor computations are getting a little better.
Um but still, I find it a little bit frustrating that I cannot do uh I don't know, theorem proving on a GPU. Uh I have absolutely no idea how to go about that.
Uh and in part by by by lack of uh an appropriate language, okay? Uh uh So, I'm I'm not ready to program the GPU pipelines at the very low level myself, so So, and and I think it's more general. I think we're we're not using uh all these GPU and other highly parallel hardware as much as we could. Yeah, so verifying applications that have been learned or generated or generated by AI also and it's still a pretty hot issue.
Back in 2018 I was more thinking of of verifying simple neural networks like those used for I don't know computer vision or self-driving cars or or or some numerical computations like you know weather prediction and so on. So so specialized LLMs but you still want some guarantees about what they produce that they cannot produce completely inconsistent outputs for instance. There were some some attempts in in in the last years at using static analysis tools and basically program verification tools applied to LLMs but well it it it doesn't scale.
LLMs are big.
Sorry.
Neural networks are big.
And for LLMs there's also a distinct lack of specification. Okay.
You don't really know what's a good answer from an LLM.
Well you know it when you see it but you cannot write a mathematical specification of it. So so that part is probably over. What I would say are the big problems for today yeah probably maintaining software quality despite AI's love despite a lot of pressure to throw away traditional software development techniques using LLMs as an AI as much as we can to do mechanized proofs so proofs that can be checked by machines.
Maybe this will be the the decade of formal verification of software. We've been waiting for that for 50 years so maybe it will it will finally take off.
>> What's your top book recommendation for software engineers and why?
>> Well this this is an old one, the Programming Pearls by Jon I think I read it when I was a PhD student, but I think it's it's nice as showing how very talented programmers work, [snorts] how they think about their programs. So, it's it's it's it's a combination of choosing the right algorithms, expressing them clearly, uh knowing when to stop, when when to use a simple algorithm, where where when a more complicated one is not needed, uh having a sense of elegance in in the code you write, um uh having a feeling for where the problem is when when the the code misbehave. So, all all that kind of things that are hard to communicate, and I think those those pearls that are very easy to read, uh and and and don't use any complicated data structures, don't use any complicated language. I mean, it it's it's kind of timeless, you know.
Um I think those pearls are are good illustration of that.
Uh so, if you haven't read it, it's it's a classic, but I think it's a nice reading.
Nice read. Uh the second one is a little more controversial, I guess.
So, in the How to Design Program, which is a fairly ambitious title as well.
And this comes from the Scheme community, okay, Abelson and Findler, Flatt, and Krishnamurthi.
Um and and those people have developed uh well, the Scheme community is famous for having developed uh pedagogical resources that are I mean, ways to teach programming uh that that go beyond teaching functional programming, basically.
And so, so there was the the MIT [clears throat] Course Structure and Interpretation of Computer Programs, which was quite famous, and this is kind of a more modern twist on on on similar ideas.
And and and I find this book interesting because well, it it it really teaches you the way of functional programming a way to functional programming. It can be very irritating sometimes, very opinionated, very um almost mystical sometimes, but but it's also another great attempt at at trying to communicate how experienced programmers go about uh designing a program uh even before writing the first line.
Okay. And and then how given a language like Scheme, which is pretty flexible, how the code kind of follows uh naturally.
>> You know, knowing what you know now, if you could go back to when you just started your career and give yourself some advice, what would you say?
>> Sometimes I got that uh maybe I specialized a little too early in in in um in programming language research.
Uh maybe well, there there are some topics that are I didn't learn because I didn't feel like it. And and that I had to relearn later or I still have to learn now that I'm almost 60 and maybe not not as um uh not as quick uh as I was back in the day. So, yeah, maybe I I did specialize a little too early. And so, I would encourage everyone to get a everyone who's serious about working in computing uh to get a fairly diverse computer science background. Even even for topics that look super theoretical and are not very uh relevant to uh to everyday uh jobs.
Uh well, we mentioned the computability for instance things like the halting problem and so on. You're not going to run into that very often, but it still gives interesting perspectives, I think.
And then it also helps understanding new problems.
Like with quantum computing.
What can you do with a quantum computer that you cannot do with a normal computer?
And and and it's it's time to to revisit all of the classic complexity theory I learned earlier and when when I was young. And and so yeah, I think I think it's good to have those this kind of background even if it's not obvious you will be using it everyday.
And and sometimes I wish I had taken time to accumulate a little more of this background before specializing in in programming languages.
>> Awesome. Well, thank you so much for your time Professor Liwei. I appreciate it.
>> Thank you Aaron. That was nice.
>> Hey, thank you for watching this podcast. If you liked it and you want to see the show grow, please support with a comment or a like.
Also, if you have any recommendations for people you want me to bring on, please drop a comment. Guests like Barbara Liskov, Mike Stonebraker, Mark Brooker, these were all people that I brought on because someone left a comment. On another note, aside from the podcast, I'm working on building the ergonomic keyboard that I wish existed.
Here's a glance at the prototype. It's a split keyboard, so there's two sides.
Um this is in the case. But yeah, we launched on Kickstarter and we hit our goal within 8 hours of launching. I really appreciate it if you were one of the people who grabbed one of the early units. Um we're now working on the long journey of building the tooling now. And so if you still want to pick one up, I've left the late pledges open on Kickstarter, so you can grab one there.
I'll put a link in the description.
Thank you again for watching the podcast and I'll see you in the next episode.
Related Videos

TOP 15 Data compression Interview Questions and Answers 2019 Part-2 | Data compression | Wisdom jobs
wisdomjobs
281 views•2019-06-28

CTS 158: 802.11w Management Frame Protection
ClearToSend
4K views•2019-02-04

NDSS 2019 Send Hardest Problems My Way: Probabilistic Path Prioritization for Hybrid Fuzzing
NDSSSymposium
496 views•2019-04-02

How realistic is Cities: Skylines?
CityBeautiful
159K views•2019-02-14

GUIs & TUIs: Choosing a User Interface for Your Python Project | Real Python Podcast
realpython
2K views•2025-04-04

The OSI Model - Explained by Example
hnasr
225K views•2019-05-12

Cloud Computing - Introduction
elithecomputerguy
98K views•2019-10-07

From Traveler's Dilemma to Dynamic Routing | Demystifying Networking
IITBombayJuly
5K views•2019-08-04
Trending

WOW! Judge TURNS THE TABLES on Trump in His OWN $10B LAWSUIT!!!
MeidasTouch
197K views•2026-07-23

Playstation NO DISC/NO BUY Fight Is Over...
DavidJaffeGames
4K views•2026-07-23

Steam and Xbox Just Dropped The Hammer On PlayStation
OhNoItsAlexx
9K views•2026-07-23

Americans Confused in Australia for 17 Minutes Straight
IWrocker
17K views•2026-07-23