https://mukulrathi.com/create-your-own-programming-language/...
https://jaked.org/blog/2021-09-07-Reconstructing-TypeScript-...
I read through the first 10 chapters of TAPL, and skimmed the rest. The first 10 chapters were good to remind myself of the framing. But as far as I can tell, all the stuff I care about is stuffed into one chapter (chapter 11 I think), and the rest isn't that relevant (type inference stuff that is not mainstream AFAIK)
This is also good:
https://github.com/golang/example/blob/master/gotypes/README...
And yeah some of us had the same conversation on Reddit -- somebody needs to make a Crafting Interpreters for type checking :) Preferably with OOP and functional and nominal/structural systems.
---
Also, it dawned on me that what makes TAPL incredibly difficult to read is that it lacks example PROGRAMS.
It has the type checkers for languages, but no programs that pass and fail the type checker. You are left to kind of imagine what the language looks like from the definition of its type checker !! Look at chapter 10 for example.
I mean I get that this is a math book, but there does seem to be a big hole in PL textbooks / literature.
Also I was kinda shocked that the Dragon Book doesn't contain a type checker. For some reason I thought it would -- doesn't everyone say it's the authoritative compiler textbook? And IIRC there are like 10 pages on type checking out of ~500 or more.
It might not have the same lingo as the modern type checking specification but most of the ideas are there. It talks about type systems, type expressions, type rules, constructed types like array/struct, type variables for unknown types, etc. It puts the type rules in the grammar productions. It stores the type info in the AST nodes. It uses the chained symbol tables as the type environments.
It has sections on type conversion, operator/function overloading, polymorphic functions (parameterized types), and type unification.
It has all the pieces and steps to build a type checker.
https://www.amazon.com/Compilers-Principles-Techniques-Tools...
It has 11 sub-sections, 2 of which are about type checking
6.3 - Types and Declarations, pages 370-378
6.5 - Type Checking - pages 386 - 398
So that's about 20 pages out of 993 pages. A fraction of a chapter!
---
What I was referring to is the appendix "A Complete Front End", which contains a lexer and parser, but not a type checker! Doesn't sound complete to me.
I guess they have a pass to create the three-address code, and type checking is only in service of that. But they don't give you the source code!
---
Also weirdly, when you look at the intro chapter "The structure of a compiler", it goes
1.2.2 Syntax Analysis
1.2.3 Semantic Analysis (3 paragraphs that mentions type checking and coercions)
1.2.4 Intermediate Code Generation
But when you look at the chapters, there's NO semantic analysis chapter! It goes from (4) Syntax analysis, (5) Syntax-directed translation, to (6) intermediate code generation.
I think there's a missing chapter! (or two)
WTF. The 2nd edition is really butchered.
What the heck happened ...
The second edition cut a bunch of C++ material out.
And yeah I don't think I missed anything -- I think it even had better diagrams.
So yeah I believe that general rule! I didn't realize that at the time I bought the Dragon Book.
Pretty sad how you can lose knowledge over time!
---
The books also respond to fashion -- e.g. Java was a popular teaching language, so they had to add more Java. I think that is reasonable in some ways but can backfire in the long term.
Although I guess I am not too excited about MIX assembly in TAOCP and so forth, so it's a hard problem
Books also tend to become more sparse on the page, and with more pointless “illustrative” stock photos that add nothing and take up page real estate (leading to more advanced topics being dropped to reclaim space), but make the book seem more approachable to undergraduates.
Generally applies more to physics, chemistry, and math books than computer science, but it is a general phenomenon.
Edit: by "screwing up semantics" I mostly mean the combination of overloading and implicit conversions, which is known to cause issues in Java, C++, etc.
Basically, the existing material is a bunch of existing incredibly complicated implementations, the odd blog post that just throws a bunch of code your way without really explaining the why/thought process behind it, and books that aren't worth the money.
The result is that you can of course piece things together (as I did), but it leaves you forever wondering whether you did it in a sensible way, or if you constructed some weird monstrosity.
To put it differently: you can probably build a garden by digging some holes and throwing a few plants around, but without the right resources it can be difficult to determine what the impact of your approach may be, and whether there are better ways of going about it. Oh and I'm aware there are resources on gardening, it's just a metaphor :)
The Dragon book has a chapter on type checking. It gives explanations on many topics. It has plenty of examples. It has type treatments on different areas of a language, like expression, array, struct, function, pointer, etc.
Despite being really old, its ideas and explanation on the topic are still relevant.
So that leaves blog posts for most developers actually implementing this stuff.
But the solution here is that when you finally figure out a good strategy to deal with something muddy like this is to write that better blog post :)
As for _when_ I'll do that, that depends on when I can convince my inner critic to actually commit to the idea :)
[1]: https://github.com/yorickpeterse/pattern-matching-in-rust
But that's an exception, and deliberately decided to be complex.
- Generics, especially inferring generic type params
- Recursive types
- Deeply mutable vs immutable types
- Type refinement based on checks/usage
- Giving good error messages for deep type mismatches (though I'm not sure TypeScript itself has figured this one out yet, lol)
etc. And even the stuff I've figured out, I figured out almost all from scratch (sometimes having to bail and take a totally new approach midway through). I would love to read a book giving me a proper bottom-up walkthrough of the current landscape of type system implementation
If you want ML-style total type inference when you expect the compiler to deduce the parameter and the return types of your functions, then yes.
Local variable type inference isn't hard at all, unless you want to do stuff like Rust: declare a variable without an initial value and infer its type from the first assignment downcode.
EDIT: ChatGPT could actually demonstrate the whole process for type checking small chunks of code, including: assigning them type variables, collecting constraints and then unification. It would even then point out if there was a type error in the code snippet!
https://gilmi.me/blog/tags/type%20inference
If you find that helpful, I've made more content on compilers (including live coding a compiler, without narration) which should be easily reachable from my website.
Simon Peyton Jones together with others wrote a relatively easy to read book about the writing of Miranda (Haskell), which even includes a simple explanation of lambda calculus, so it includes everything you need to know about the theory, more or less: "The Implementation of Functional Programming Languages" 1987, https://www.microsoft.com/en-us/research/wp-content/uploads/...
The book Applicative Order Programming: The Standard ML Perspective has you implement an ML-like language at the end (the book is mostly about programming in Standard ML itself). Chapter 10 covers type checking and type inference. Chapter 11 covers interpretation via graph reduction. Chapter 12 covers compilation of the ML-like language to an abstract stack machine. The code is all in Standard ML. It's very direct and practical without getting bogged down in theory, although it does talk about theory, and it's not as gentle and fun as Crafting Interpreters.
It was published in 1991. It's on libgen; I'd recommend downloading a PDF and reading those chapters in order to judge for yourself.
I don't think an ML-like language is the best option. I would start with type-checking something simple like C or Pascal: no overloading, generics, type inference, anonymous functions. Just plain old subroutines and declared types on everything, arrays and structs as the only composite data structures.
Then you could add implicit conversions, type inference for locals (not that hard), subtyping, target type inference for anonymous functions, generics and maybe overloads if you're brave enough.
So this is actually harder to do that it might seem. The best advice I have is to contribute to a compiler or two and understand their semantic checking model.
I bought _Practical Foundations for Programming Languages_ by Harper and _Types and Programming Languages_ by Pierce and I just can't get through the first few pages of either of them. I would love to see a book as gentle and fun as _Crafting Interpreters_ but about making a static ML like language without starting with hardcore theory. (Bob, if you're listening, please make a sequel!)