By the way, the argument that "a sufficiently intelligent compiler
should optimize this away" is a dangerous one that has caused much grief in the past in the field of programming languages and compilers. It is better to plan for the worst (i.e. what we know is doable) and hope for the best (i.e. what we are trying to demonstrate).
Except that we are designing the compiler here, and I still think my point stands. A simple flow-insensitive whole-program analysis could deduce those facts. That being said, I agree that we could use special compilation modes for the compiler code. We will have to, in fact, to allow access to low-level primitives the rest of the JS code shouldn't have access to.
I'm not against an OOP style, but as I say there is more than one
way to express OOP in JS.
The canonical way is definitely the x.meth() style, however.
The namespace could be implemented by having the compiler
automatically append a prefix to all the global names it sees, with a prefix that is a command-line option of the compiler. So all the compiler's code would be in the compiler's namespace. Note that the prefix could be something like "%tachyon_" (which is illegal in pure JS), so that no interference with the application is possible.
This is starting to sound like C++ name mangling. We could perhaps implement it as separate "global objects" (top level JS environments), with the global objects being essentially unnamed (and therefore, making Tachyon invisible to the normal JS code), and the special tachyon primitives appearing only in its own environment. The tachyon global object could have a pointer to the JS global object in its own top level environment, as well as primitives to inspect and modify it, as well as its own top level environment.
This is not necessarily bad, because it highlights the use of
virtual methods. Moreover, this can still be hidden in a toplevel function if that's desired
I'd rather not hide it. In fact, I think I'm OK with the idea of non-method operators so long as you're OK with using virtual method calls where appropriate. I simply don't want our coding practices to get in the way of the simplicity JavaScript has to offer.
This "bootstrapping business" is part of our research objectives and
is (probably) an important part of Erick's MS thesis! I can guarantee that using C/C++ will cause problems (as we have discussed previously).
I know it's important and I've taken a liking to the idea. I'm simply saying that I don't think we should take the more complicated approach at every turn, because then, we are really making our life much harder.
I understand you are trying to demonstrate this in your Ph.D. I
think it is much harder than you think ("simple flow-insensitive analysis"). Perhaps you should look into this soon to explore how it can be done for JS. This will shed some light on the issues specific to JS. Unfortunately, you can only prove this for sure by building a compiler and implementing your ideas. I guess we have a chicken and egg problem!
I'd like to start working on simple analyses soon after we have implemented an intermediate representation. We have a parser in progress, we need to design an AST, and after that, I'd like to work with you and Erick on designing a high-level intermediate representation we can transform the code into. Something that will be easy for analyses to work with, and that we can progressively translate into a lower level IR, and ultimately machine code, hopefully all within the same framework.
By the way, how can fields be marked as "read-only" in Javascript?
In the JS standard:
15.2.3.6 Object.defineProperty ( O, P, Attributes )
Attributes would be something like { Writable : false }
I don't think the syntax is very convenient, but it's possible.
Imagine a 2D point "class" with 2 fields (x and y) and 20 methods
(add points, compare points, print points, magnitude, etc). That would entail a 1000% space overhead! That is significant. A similar situation could happen for Tachyon, think of an AST node class where AST nodes have few fields but a large number of methods. In a fancy compiler, it is not unusual to see very high memory usage in the analysis and optimization phases (for doing various flow analyses). GCC for example can use gigabytes of memory for compiling some programs. If we use 10 times more memory than we need to this will hinder the kinds of analyses the compiler can perform and prevent us from achieving our objectives.
The AST classes are precisely the classes that will need virtual methods, however. Fortunately, there will only be a need to store methods that are redefined for the leaf nodes of the AST tree. The others will already be defined up the prototype chain... And hopefully we can work on optimized object representations at some point, and make it so that constant fields for a given class can be stored in the class rather than the object itself.
This is a case where I really think we should go with the natural OOP style, at least at first... Because AST and IR nodes will be used all over the place, and we do want the code to be simple and concise.
- Maxime