5 ms·
Big shout out to "Writing an Interpreter In Go". I followed along for about a month. The code is clearly written and tested. It's practical enough with theory e
by hiepph 4y ago
Big shout out to "Writing an Interpreter In Go". I followed along for about a month. The code is clearly written and tested. It's practical enough with theory explanation along the way. Now I feel confident to write a Lua interpreter in Go (considered Lua is simple enough).
- moron4hire 4y agoThere is a popular saying (especially amongst The Olds) that "you don't understand programming until you understand pointers." I found it to be the opposite: I didn't understand pointers until after I had been programming for years and then implemented my first, interpreted scripting language. I think learning to write interpreters is one of those fundamental skills that everyone should learn at some point in their programming careers. Not because there's a good chance they'd create a popular language out of it (though who knows, I definitely think we could use some new ideas in PLT), but because it removes almost all of the "black magic" feel of programming. You see arguments for days about "OOP vs FP" and other such faff. And once you've implemented OOP and implemented FP in your own language, it's all just... window dressing. It's all the same thing, just different ways of slicing it. There's nothing inherently evil about one or the other.
- ammanley 4y agoRandom question from someone who is is self-taught and doesn't know better: is there a significant difference in this saying about learning interpreters vs learning to write your own _compiler_? Or are the two functionally equivalent for learning purposes?
- stcredzero 4y agoI'd say that either one is good. Writing your own compiler, depending on how you do it, will get you into assembly and machine language, which will benefit your understanding of the lowest levels of computers, and of the low-level mechanisms behind concurrency and operating systems. You can always do a 2nd project with your interpreter, where you compile down to a bytecode, then JIT the bytecodes to machine language.
- ammanley 4y agoI do like that idea, thank you.
- moron4hire 4y agoI'd say there's probably about 1/2 to 2/3rds overlap between the two. You'd still need to do all the same lexing and parsing. You still need to create a model of execution for your language. But the primitive substrate of the machine (be it real or virtual) turns implementing that execution model into a puzzle all its own. You might implement an array in your interpreted language as just an array in your host language. You might implement an object as just a HashMap between field names and values in your host language. Interpreters don't have to build their own interfaces with the operating system, they reuse those interfaces from the host language in which they are developed, but a compiled language will need some way of its own to execute system calls. Like, printing some text to a terminal. Say we were implementing an interpreted language in C#. We get to the point of writing our own "print" function for our own language. We'll probably end up creating some kind of translation from our language's print format to some kind of call to System.Console.WriteLine in C#. You might even like the format of Console.WriteLine, so you might even make it a straight, one-to-one translation and call it a day. But if you're writing a compiled language, you'll need to know how the operating system you're running on expects to receive and execute commands. That's a whole other thing. To grossly oversimplify, it largely means getting a bunch of bytes into the right format and order into memory and then executing a specific CPU instruction. Want to allocate memory? There's another blob-of-memory-plus-execute-an-instruction interface you'll need to adhere to. Want to open a network socket? Same. And modern operating systems provide a lot of functionality. But also, a lot of that work is kind of grunt work. There are certainly ways you can design a language that make it more difficult to implement as a compiled language than an interpreted one (dynamic typing, for example). Let's gloss over that issue. All else being equal, the language portion of the work being done in interpreters versus compilers is largely the same.
- ammanley 4y agoReally appreciate the through review, this sheds a lot of light on things for me. Thanks a ton.
- 13of40 4y ago> ...Want to open a network socket? Same... From your compiler's perspective you shouldn't be messing around with all that, you should have an abstraction that lets you say "Pass a by value, b by reference, and c as an out parameter using calling convention X". As long as malloc and opensocket or whatever use the same calling convention, all of the actual byte layout is a one time effort.
- tylerscott 4y agoI second your opinion that learning to write an interpreter is a great idea at some point in a career. It definitely helped me gain a new level of understanding and, well, confidence in my knowledge of how pretty much any language “works”. It makes everything more interesting, too!