Page 1 of 2
What advantages are there to implementing a dynamic language for the .NET platform and the DLR? How does it work? What better way than to ask someone that has already done it.
First what exacly is IronJS and for that matter what is an "Iron" language?
Now that we have the background to the project, its time to ask some questions:
NV:What is the advantage of porting a dynamic language to the .NET platform?
FH: I think the main advantage is just the DLR, I was investigating an implementation on top of the JVM at first, this was back in early 2010 if I remember correctly. The DLR gives you a lot of really great stuff for free.
NV: Like language interop and what else ?
FH: That is one thing for sure, but also just how solid the DLR code is and how big of a piece of the technology it solves for you (emitting the IL)
NV: DLR has a reputation of making it easy to create a new language implementation. Why is that? Does it provide better parsing facilities or is it in sense that the language implementer can borrow facilities out of the box like the CLR GC or JIT?
FH: The DLR itself doesn't give you anything related to parsing or lexing, but rather lets you turn your AST into what they call an Expression Tree, which is a high level, object oriented version, of IL. In reality, the expression trees are syntax trees, but they are compiled to IL by the DLR and while emitting IL isn't a complicated task, it's time-consuming to write code that does it. So, getting that for free, is a big thing.
NV: After emitting IL, is it compiled or interpreted by the DLR at runtime?
FH: Well, that's pretty much one process, you hand the DLR your expression tree, it gives you back a delegate which you can invoke. The delegate itself can either be interpreted by the DLR or compiled by the JIT; it's something you specify when you compile it.
NV: At the backend how does language interop work? Is every language creating its own AST which is then transformed to a DLR tree which acts as the common language denominator?
FH: Yes, that is pretty much it. There are special classes/objects called binders which take care of the language inter-op. A binder basically defines how a language implements the binary add operator, or the function call mechanic, etc. However, IronJS does not use these binders as they are "slow".
NV: So what alternative does IronJS use ?
FH: There's basically two ways you can use the DLR, either full-out and you use all the associated binders and all other DLR stuff which basically gives you free inter-op with all other Iron* languages; and while this is great, a lot of these mechanics are pretty slow. So IronJS uses the DLR as an IL generation and compiler tool and I do my own binding, that is ironJS specific.
NV: That's pretty deep...so how can I access the IronjS libraries from C# ? Do I have to go through a hosting process?
FH: The inter-op is a bit "so-so" currently, it's something I am working on (whenever I have time), but yes there is a hosting context
NV: How would C# types be mapped to IronJS ones and vice versa?
This is something we're working on making better Forward the calls/property accesses back and forth between JS/C# I mean
A lot of sacrifices was made in IronJS to make it as fast as possible, which means some functionality ended up being sidelined, sadly
NV: So can you take us through the design process of how you made IronJS ? (like parsing to create the AST and how you end up with a DLR tree etc)
FH: IronJS was something I've been thinking about building for a long time, but I ended up changing the way it worked many times over before it was done. The 0.2 version available on github is completely hand written, earlier versions had a generated lexer and parser but they ended up being too slow.
But, it's a very standard control flow:
- Read all the input into a buffer
- Run a lexer across the input to produce a list of source tokens
- Run a parser over the list of tokens to produce an AST
- perform a bunch of optimizations/analyzes on the AST
- Create a DLR expression tree
- Hand the DLR tree of to the DLR itself for compilation into a delegate