Letter to a Young PL Enthusiast
axisofeval.blogspot.com
axisofeval.blogspot.com
Might want to skip the low level stuff and quickly get to business with high level libraries like the Dynamic Language Runtime.
[1] http://en.wikipedia.org/wiki/C-- [2] http://www.llvm.org [3] Yes, I've got a thing for LLVM. Can you blame me?
As an educational experience doing everything yourself from the machine code layer up is great, but for getting stuff off the ground it's not.
IMO the big advantage of using a mature existing VM is the library. It should be possible to have at least a usable GC (say simple mark-and-sweep), code generator etc. without too much effort.
I'm also working on a cross-language compiler and have a question about TCO, specifically tail recursion. Currently my language compiles a tail-recursed function's body into a while loop. Don't Scala and Clojure do the same, except using the actual bytecode?
I know Scala does it at function level (i.e. the function calls itself at tail position). I think Clojure have a 'recur' keyword to similar effect. The issue with JVM is that if f() calls g() at tail position and g() calls f() at tail position, it can't be optimized away (at least not without an undue amount of work so the advantage is lost). Clojure uses a trampoline[1] based approach to handle such a situation. I think Scala 2.8 also adds support for that. This works well with constant space, the only issue is that its a performance hit as its not done by the VM.
[1] http://richhickey.github.com/clojure/clojure.core-api.html#c...
And I get a warm fuzzy feeling from doing stuff myself (although I'll use the Boehm GC and compile to C for my next language).
And LLVM is effectively a huge black box, which I would caution any new language implementor against using. Sure, it may get you off the ground easier, but that's because you'll no longer be standing on the ground, you'll be standing on LLVM, a massive codebase you don't understand nothing about.
You think people should rather worry about getting lexical scope right, then why should they worry about the low level details? Sure, they have to have at least some idea about how it works on the lowest level, but they don't have to know all the stupid man-given details. Choosing LLVM over x86 assembly is good for performance and productivity. Performance with LLVM will be better unless you are going to spend an extraordinary amount of time to build better low level optimizations, register allocation and code generation than LLVM.
The point of doing the low-level projects is to learn for yourself, not to literally create the best new language (but you never know.)
A backhanded way of saying C# is really nice.
There seems to be a siren's call of language/OS/editor development, though. If you really can't resist it, go do it. At the very least, you'll learn a lot, and it beats CRUDscreen Web2.0 apps as a mental exercise. But other fields of CS are much, much, more useful.
...but if you had to choose, I'd say to learn Python so you can prototype quickly, and then C++ so you can make it run fast in production. The two also have the nice benefit of working quite well together, so that you can push things into the C++ layer as you understand them better, and keep experimenting by gluing together those libraries with Python.
The math and the algorithms are important - but one shouldn't dismiss a fundamental understanding of the lower levels of the system - even though they'll change over time and you probably won't have to "go there". Real-world software runs on real-world systems, and there is no reason for a budding computer scientist to deprive himself of at least a cursory understanding of how things work underneath - you never know when he'll want to break out of the toolset Vendor X provides him and do something radical and new (like implement something in hardware, or recognizing there is some feature there he can use to massive real-world benefit)
And go for it. There's no better way to learn CS.
you must create a programming language, or be enslav'd by another man's.
William Blake allusion FTW!
Nothing at all is lost.
"I must Create a System, or be enslav'd by another Man's; I will not Reason and Compare: my business is to Create"
From "Jerusalem The Emanation of The Giant Albion":
http://www.blakearchive.org/exist/blake/archive/work.xq?work...
You'll need it anyway. And it will provide /much/ insight into your mistakes.
Languages are important to the extent that people decide to learn them and use them, and that way lies politics.
Re JavaScript, I'm referring to the lowlevel nature of many of its constructs:
- its impoverished way to pass parameters (i.e. there are no keyword parameters; you don't get an error if you pass too many or too few arguments)
- its impoverished exception handling (i.e. you can't catch exceptions of a specified type)
- its impoverished standard library and built-in data structures
- its lowlevel and complicated OOP system
There's more, see http://pwpwp.blogspot.com/2009/08/awesome-helma-and-lacking-...
Re Python and Ruby, I'm mostly referring to the fact that both languages started out with broken lexical scoping, and had to change their scoping rules repeatedly, which is a huge red warning sign. Additionally, it seems very hard to implement both languages so that they run fast, another factor. Ruby also has an array of different kinds of first-class functions (blocks, procs, lambdas, I lost track), with different capabilities and restrictions, which is a design failure to me. That said, I think they're acceptable languages, even if they force you to memorize a lot of irrelevant stuff.
- You can emulate keyword parameters by passing an 'options' dict, and you can emulate defaults by 'var myOpt = options.myOpt || default". You can also define a function, like $.extend, to do this for you.
- You can catch exceptions of a specified type by checking the type and rethrowing if it's not appropriate. And you can define a function to do this for you:
function try_catch_if(exc_type, body, exc_handler) {
try {
body();
} catch (e) {
if (e instanceof exc_type) {
exc_handler();
} else {
throw e;
}
}
}
- You can define your own standard library a la JQuery or YUI, or even modify the built-in one a la Prototype (though I don't recommend this). And the built-in data structures aren't all that bad.- You can build whatever OOP system you want on top of prototypes, and many libraries do just that. (In this respect, it's quite similar to Scheme, where every programmer starts by defining his own incompatible object system).
Most of the sucky parts of JavaScript come from it introducing things that weren't really thought through, eg. the 'this' keyword nonsense is ridiculous, as is the lack of argument-checking by default.
I'm just saying this "flaw" doesn't make any sense as such. If you want to tell me that with some perspective it's a flaw, show me the perspective, because I'm not seeing it at all. It looks pretty ridiculous on my end.
However the hashtables are broken: they say they're empty, but they have 'constructor' as a key when you create them.
I'm not sure which part you didn't understand; this is my best guess. I believe the author is trying to say that syntax is a superficial appearance, and not relevant to - indeed, a distraction from - understanding the true beauty or ugliness, utility or disutility, of the concepts embodied in a language.
Thanks for the explanation. It seems the author and I have got a similar view on syntax (how can we not since we both seems to admire Alan Perlis!).