Rhine – A Lisp on LLVM
github.com
github.com
Another remark, is that it would have been nicer to have the language being made in itself instead of OCaml.
Other than that, very nice work.
and contrariwise, bootstrapping a compiler might even be a net negative, not just because you have passed up on the chance to use a language that is better suited to the task, but because you have complicated your build process, created potential morasses when you have bugs with both your language design and your compiler implementation and you can't fix them separately, and are implicitly prioritising those features of your design and implementation that are useful for writing compilers, even though that might not be a very large use case for it at all.
in the days where people were building up from assembly, bootstrapping compilers made a lot of sense. but now that there are existing, well established languages that have proven their value in the specialised problem domain, it makes no sense to ignore them and insist on bootstrapping for its own sake.
For me bootstraping is the best way of testing if the language design is sound and to become independent of other tooling. As you happen to mention.
Many language designers that don't follow this process, happen to never fully experiment with their own language, as they spend most of their time in the compiler.
As for tooling, the overlying of many designers in C and similar toolchains has created the wrong belief that only the said languages can be used to write compilers. To the point of the famous statement in the language design community "My compiler compiles yours".
For me, the only place where bootstraping is to be avoided are DSLs.
FTR, the first version of gcc was written in Scheme, but even the c++ frontend of gcc is written in c rather than c++
Yes, but when creating a new language, the own compiler or at least the runtime/library, are the first complex applications, usually.
> ... but even the c++ frontend of gcc is written in c rather than c++
was written in C, now it is C++.
Also, compilers are a particular subset of programs - they're pure functions. By bootstrapping do we end up with nothing but languages suited for this kind of problem?
http://tratt.net/laurie/blog/entries/the_bootstrapped_compil...
If your goal is to write a language that is very good for writing compilers, then bootstrapping is probably a great idea. If you have other goals, such as being well suited to CRUD applications, concurrency, parallelism, graphics, you may find that bootstrapping is not the most productive activity.
More broadly, if your goal is to produce a useful language, why would bootstrapping help you achieve that goal, beyond writing any other system in your language?
Was there a language/compiler combination that you worked on where you experienced this pitfall first hand, are there historical anecdotes from language/compiler authors, or did you arrive at this a priori?
As the author of a computer language expert system, I refer to its rules language as a meta-language (and rules as meta-code) because it manipulates language content symbolically. And, as it happens, it actually executes BNF in order to parse the languages it consumes, the BNF being delivered to it via that same rules language.
Code content represented in my system's Internal Representation (IR) is not itself a meta-language; it's more of a "super-language", being synthesized across real languages. But that IR's architecture does comprise a kind of meta-language; because it is a structure that represents language content in an abstracted way, it is "about" the very concept of a computer language.
As the author of such a system, I do meta every day, meta-meta often, and triple-meta occasionally.
Sounds like an interesting project. I didn't point ML to say that meta-languages generally or ML itself were useless. Rather, that ML is specialized in a way that wouldn't aid in writing things completely unrelated to compilers. (Tho I hadn't thought of using one in an expert system.) Say, writing relational databases, game AI's or GUI interfaces.
http://tomlee.co/2014/04/03/a-more-detailed-tour-of-the-rust...
At the time of writing, Rust would use LLVM to generate object files from LLVM IR, then link 'em together using the system's C compiler.
Facebook wrote the compiler for their Hack language (basically a better PHP) in OCaml, for example.
Bootstrapped compilers are nice but can come later, after the language gains traction in the community. This language is brand new.
One of the selling points of Clojure is that it embraces the libraries of the targeted eco-system.
The Clojure community has some time ago discussed addeding conditional support, to be able to build common libraries across multiple runtimes. Similar to what Common Lisp offers.
Yes, yes. LLVM definitely helps here. But it doesn't come "for free", which is what the GP post asked. You still need some "glue" code to make it work.
Yeah, but that only appeals to the people who are already committed to the JVM (or .NET), and that is a shrinking population. There's a whole layer of complexity to deal with managed code and OOP languages and there's a bit of a impedance mismatch between a Lisp and a Java-style library and the VM itself.
For people working with native code or otherwise not in the JVM ecosystem, Clojure is not really ideal.
Looking at the enterprise world, I would say it is still growing.
But you could provide some kind of source if you disagree, all the statistics I've seen have had Java and JVM languages in a steady downward slope for the past five years or so.
It is a international consulting company that does large IT projects, mostly multi-site. You can imagine the possible candidates.
We only get JVM (only Java) and .NET (C# / VB.NET) requests for proposals for greenfield projects. Any other platform requests tend to be pure data spikes.
I know it's anecdotal but what platform do you actually think enterprises are using ? Companies are looking for cheaper options so .Net isn't exactly on fire.
I work with Fortune 500 companies that have 100% Microsoft stacks.
MSDN yearly licenses are a drop in the ocean in these companies.
Jython would be by far the least used of those alternatives, whereas Scala the most used. Clojure's coming up strong, JRuby's making slow inroads, Kotlin's getting some traction at Ceylon's expense, whereas Groovy's on the slide.
I chose OCaml because of the relatively mature OCaml-LLVM bindings. A self-hosting compiler is a lot of work: it'll require Rhine-LLVM bindings first.
1. Set indent-tabs-mode in all modes which use that variable. So, if I install a hs-mode, the indent-tabs-mode in my .emacs should be the one that it picks up.
2. Add multiple independent hooks to c-mode-hook from different modes.
3. Change the global keymap in different modes, as and when they are loaded.
Isn't mutable variables the most obvious way to solve these problems?
Yes, but the mutation can be entirely limited to the reference. The data structures do not have to be mutable. It's a trade-off, of course, because you can't pass somebody just part of a data structure (like a sub-map) and have them mutate it there, but I think Clojure has shown that in practice this isn't really much of a loss.
(Not being snarky, languages and text editors are both interesting projects and worth experimenting with, and combining the two is especially interesting to me.)
emacs, which is utterly unapproachable for newcomers, and will always be uncomfortable to use for people that grew up with "modern" desktop GUIs, because it and most of its userbase predate established interface standards and they like it that way.
DrRacket, which is a step in the right direction but is Racket-specific, bloated, slow, and somewhat buggy.
LispWorks, which is proprietary and prohibitively expensive unless you sign up for and are allowed to use the crippleware version.
Given those choices, it's not surprising that most people just give up on Lisp and use languages that you could comfortably program in Notepad if you had to.
Clojure has a layer of complexity originating from the JVM background. It makes sense to not to use the Clojure codebase as is.
JVM is the reason I am not using Clojure. I can't be the only one in this position. I need interoperability with native libs, JVM is just a hindrance for me.
> Another remark, is that it would have been nicer to have the language being made in itself instead of OCaml.
Definitely, but bootstrapping a language is quite a lot of work. Makes a lot of sense to build the "Stage 0" compiler using O'Caml or Haskell (which are excellent languages with good libs for building compilers).
If it catches on, I'm sure this project will eventually become self-hosting.
I don't think this is a good approach and it's very nice to see projects like yours that try to shift the paradigm. LLVM can provide many of the benefits of bytecode based VMs, yet give efficient native code in the end.
How did you go about the GC? Did you grab a GC from somewhere else or build your own? Did you use LLVM shadow stacks and/or GC annotations? I guess Lisp is a lot easier to build a GC for than other languages.
There are many promises VMs should give, performance, safety and security but in practice not a lot of those promises were ever fulfilled. Performance can be on-par with native code in the best case but usually 2-10x behind, safety may be a bit better but we still get crashes because of incorrect memory use and the Oracle JVM has had more zero day vulnerabilities than any other software I can name. I think it's time to move on.
I really think Java did a left turn there, by not providing native compilers as part of the standard toolchain.
At least .NET has NGEN and now will get .NET Native compilers as well.
Yes, Sun/Oracle JVM had quite a few security vulnerabilities, but many were caused by the native code in the VM stack. While others were indeed caused by real bugs in library code. Still way less exploits that in C and friends.
Besides that was one JVM, there are plenty of others out there which share 0% implementation with Oracle's.
I don't do GC yet.
I suspect it happens because the VM becomes too large and complex for anyone to debug.
Have you checked out CFFI/Common Lisp ? I've heard Chicken Scheme and Bigloo are also quite good when it comes to this.
I am not familiar with elisp but from first google result it reads that the equivalent is alter! / swap!.
(deftype SomeTypeWithMutableFields [^:unsynchronized-mutable some-mutable-field ^:volatile-mutable another-mutable-field])
:unsynchronized-mutable corresponds to a normal mutable Java variable, and :volatile-mutable corresponds to a Java variable with the volatile modifier.
They are private by default, you can only set! them within the lexical scope of the deftype definition. If you needed to expose fast host mutation to the public, I would create a setter/getter interface (via definterface) and implement it on your deftype and use set! locally to mutate the field there.
Agreed, but also:
- The ISeq abstraction
- Software Transactional Memory for state management
- Structure-sharing of the persistent structures, for added efficiency/performance
And of course, all the nice reader macros that make things so much easier to read.
This project is cool, but what I'd rather see is Clojure becoming parasitic, living on all the host VMs it can. We've got the CLR version, and ClojureScript for V8/JS, but we could also have it properly on top of Python, Ruby[1], Lua, Erlang, and LLVM.
[1]: I know Rouge exists, but I'm not sure how well it's progressing.
Apparently implementing Clojure on the LLVM is no easy feat though; judging from references to previous discussions on the mailing list. [1] There is some work on it already though [2,3,4] and I'm sure we'll get there eventually.
[1] https://groups.google.com/forum/#!topic/clojure-dev/bex25u9h... [2] https://github.com/ohpauleez/cljs-terra [3] https://github.com/halgari/clojure-metal [4] https://github.com/halgari/mjolnir
A real compiler backend takes a bit more than a weekend project, and it is hard to know the real reasons, technical or personal life of the coders, for the current state of the projects.
I think the structural sharing is the definition of persistent data structures, as distinct from immutable data structures in general.
Oh, yes, you are very much correct. I just wanted to highlight that is itself a feature of Clojure's behavior.
Unlike Rhine, it's not Clojure inspired though.
So this sounds pretty interesting.
(Reference [1] in that email points to: https://github.com/elliottslaughter/rust-gc-notes, which documents difficulties trying to build a precise GC for Rust on top of LLVM.)
Unfortunately, as far as I can tell, it's defunct outside of its use in the GHC. E.g. the Quick C-- compiler was recently archived here https://github.com/nrnrnr/qc--
I didn't know SBCL did that. Cool.
http://www.lispworks.com/documentation/HyperSpec/Body/f_disa...
Sadly, it doesn't seem to be as tightly integrated as what you'd see in SBCL from a developers PoV, but I'm certainly intrigued by their ability to achieve some very specific implementation while separating it from the expression of the algorithms.
If C is not "low level" enough what are you looking for?
(It occurs to me, the C code can be compiled with clang, which provides further opportunities for low-level output.)
There's also the issue of alignment with the usage of 1-bit and 1-byte types...