
Direct Clojure to C Compiler - Based on ClojureScript  - espeed
https://github.com/schani/clojurec
======
exDM69
Clojure is one of the cooler languages out there. There has been one major
blocker for me, though: the JVM. I don't want to have anything to do with the
JVM. Not because it's bad. It's just that native code is better, especially
for the stuff I'm doing.

I hope these developments eventually turn into a proper Lisp that you can
interface with native C code efficiently.

Racket is pretty cool too.

~~~
alberich
I wonder what would be the advantages of using Clojure without the JVM over,
say, Common Lisp. To me, it seems the great advantage of Clojure is its ease
of using the large number of java libraries out there. However, if you take
those libraries out, wouldn't a mature Lisp implementation like SBCL be much
better?

~~~
pjmlp
There a few differences that might be worth still.

Clojure is a Lisp-1, and provides better data structures as Common Lisp as far
as I am aware.

But the JVM benefit is a big one indeed.

~~~
alberich
I thought that, besides the JVM itself, the advantages of Clojure would be its
concurrency model - as CL standard doesn't define anything related to this -
and its stronger functional approach.

I don't fully grasp the advantages of being a Lisp-1 or Lisp-2 :)

~~~
pjmlp
> I don't fully grasp the advantages of being a Lisp-1 or Lisp-2 :)

It has to do with variable scoping. Lisp-1 only accepts lexical scoping, while
Lisp-2 also allows for dynamic scoping.

<http://www.nhplace.com/kent/Papers/Technical-Issues.html>

~~~
mahmud
Good grief.

No.

Lisp-N has to do with the number of name spaces in the language. Lisp-1s only
have ONE environment; the variables range over all values of the language,
integers, functions, vectors, symbols, strings. In Lisp-N, there are N
namespaces for each "kind" of value.

Common Lisp is called a "Lisp-2" because it separates functions from other
values. (it's closer to Lisp-5 or even Lisp-7, forgot which, because it allows
that many kinds of "names" without collission.

Also above you said Clojure "probably" has better data structures than Common
Lisp. That is unsubstantiated.

~~~
pjmlp
> Also above you said Clojure "probably" has better data structures than
> Common Lisp. That is unsubstantiated.

It is my understanding that Common Lisp lacks the vector and hash maps that
Clojure has.

Sorry if I got it wrong. I am more a ML guy than Lisp.

~~~
aidenn0
[http://www.lispworks.com/documentation/HyperSpec/Body/t_vect...](http://www.lispworks.com/documentation/HyperSpec/Body/t_vector.htm)
[http://www.lispworks.com/documentation/HyperSpec/Body/t_hash...](http://www.lispworks.com/documentation/HyperSpec/Body/t_hash_t.htm)

~~~
pjmlp
I was wrong it seems.

From the documentation I have not seen the simplified syntax Clojure uses for
vectors, hashes and sets.

I imagine that the syntax is Clojure specific.

------
DanWaterworth
I'm asking because I'm in the process of writing my own lisp->c compiler:

Are you forced to use as environment like:

    
    
      typedef struct environment {
        struct environment *up;
        int num_bindings;
        value_t *bindings [0];
      } environment_t;
    

Or would it be possible to have a dynamic vector as your environment (so that
you get O(1) lookup) at the cost of making constructing closures more costly
(as you'd have to copy the bindings)?

~~~
exDM69
Depending on what type of Lisp you're compiling, you may be able to resolve
some locations at compile time. See section "lexical addressing" in SICP
chapter 5, here: [http://mitpress.mit.edu/sicp/full-text/book/book-
Z-H-35.html...](http://mitpress.mit.edu/sicp/full-text/book/book-
Z-H-35.html#%_sec_5.5.6)

~~~
DanWaterworth
Thanks, I appreciate the link.

------
densh
At first one should expect it to be at most as fast as cpython. If you don't
do type inference and a bunch of other advanced functional language friendly
optimizations you will get quite poor performance compared to JVM. Even
haskell which does a lot of those isn't overperforming JVM yet. (Memory usage
is much better though.)

[http://shootout.alioth.debian.org/u64/benchmark.php?test=all...](http://shootout.alioth.debian.org/u64/benchmark.php?test=all&lang=ghc)

~~~
igouy
>>Memory usage is much better though.<<

"Don't confuse differences in default memory allocation with differences in
Memory-used when the task requires programs to allocate more than the default
memory."

Look at memory use for reverse-complement, k-nucleotide, regex-dna, binary-
trees, mandelbrot.

------
markokocic
Clojurescript is an interesting language, with great potential for easy
porting. I wish there is a direct JVM port of Clojurescript.

I would be able to leave with Clojurescript limitations compared to Clojure if
it provides smaller jar files and better performance of compiled code. That
would make it really usable on constrained targets like Android.

------
andrewcooke
obvious question here is: comparative benchmarks, anyone?

~~~
mark-probst
It's too early to do benchmarks. Nothing in ClojureC is optimized at this
point, so it would do very badly. I'm focussed at making it work first, then
on making it fast. We'll get there.

~~~
Raphael_Amiard
That brings an interresting other question : How far are you into making it
work completely ?

~~~
mark-probst
I'd say - optimistic estimates (for pessimistic, multiply by 2) - core
language 1 more weekend, core library 2 more weekends after that. So far it's
been about 3 weekends of work.

Contributors are always welcome ;-)

~~~
Raphael_Amiard
I'll finish up cljs/lua and i might give a hand :)

~~~
mark-probst
I'm looking forward to it! :-)

------
pjmlp
Cool, next step directly to native code skipping C. :)

~~~
jared314
Or LLVM

------
TazeTSchnitzel
Great, now you can compile Clojure to C, then back to JavaScript with
Emscripten! :P

~~~
markus2012
Sounds like a nice obfuscator.

I'm curious what the end result would look like! :-)

~~~
TazeTSchnitzel
Well, to do the full obfuscation, we would need to compile Clojure to C, then
to JavaScript, then run it through Google Closure compiler. And then try to
comprehend the mess that results.

------
goggles99
Interesting but ultimately useless. I see something like this come around a
couple of time per year. Always fades into oblivion within a year or two.

The C code will not be optimized C (like a seasoned C developer would write).
Java is compiled to byte code which is compiled to machine language. This
ugly, unoptimized, generated C is compiled into machine language too. The
performance (both memory and CPU usage) of the JVM product will be far
superior through.

Don't think that you will be writing for embedded devices or device drivers
with something like this. it will be a mess. Use C for things that should to
be done in C. For Desktop apps, Web apps, or services use Closure ETC.

I don't like seeing a square peg rammed into a round hole. It does not work
well so don't get too exited lisp programmers. This is an interesting hobby -
that is about it.

~~~
Xcelerate
Your post adds nothing of value to the discussion. You say this project will
fade into oblivion -- how do you know this? Do you know, or are you familiar
with, the developer's work?

How do you know that the C code, when passed through an optimizing compiler,
will not be able to compete with the JVM? Have you done these tests? The
author already mentioned on this page that the goal is to get it working, and
then focus on performance. As far as I can tell, he is a "seasoned C
developer" and should be able to construct the generated C so that it compiles
efficiently.

Without more than mere pessimistic speculation, your failure to contribute any
sort of primary or objective information does little more than to make you
appear curiously angry at a project in which you have no interest or
affiliation.

EDIT: Just read through your comment history. A lot of your posts are written
in this sort of negative tone. Why do you do that? If you would provide some
links or alternative viewpoints, substantiated with a paper or even a blog
post, that would be a lot more insightful.

~~~
goggles99
Poorly written C code run through an optimizing compiler will only produce
slightly better (at best) executing machine code.

Why do this? this should compile to native machine language directly if
anything. Would you transform it to C first so you could edit the C? Then what
if you want to make a big update using the Closure source? it will overwrite
your changes.

This approach is not practical, perhaps I am failing to understand any logic
as to why you would go with this approach. Portability (between processor
architectures) is all I can think of but you will never achieve competitive
performance if this is the case.

Good C coders write their code differently against different processors and
platforms because all machines have different capabilities and resources
(strength and weaknesses). The whole point these days of writing something in
C to achieve the second highest performance (only behind pure assembly
language) in both processor gpu/cpu/other co-processors and at the same time
using as little memory as possible (both ram and NV storage).

~~~
Xcelerate
Okay, now we're getting somewhere. I'm still not sure about the assumption you
make in the first line (1. that it will be poor quality C code 2. that its
compilation will result in inefficient machine code) -- we would actually need
to test it out in order to find out whether that is true.

Although I can understand your point in the second paragraph. Indeed, C is a
language that is nowadays mostly suited for performance-oriented application.
The reason the author translates Clojure code into C, and then into machine
code is that this is _vastly_ easier than going straight to native code. As
you say, there are so many platforms with different sets of instructions that
it would be almost pointless to write an optimized compiler directly from
Clojure code to all these platforms, particularly since Clojure is still a
somewhat obscure language.

The _value_ in doing this is that Clojure promotes good programming practices.
In turn, this means that someone who has little experience with embedded
systems or hand-optimizing assembly can write _better_ performing code in
Clojure -> C -> assembly than if they tried to use C without any experience.
Sure, it won't be as fast as if they were an experienced assembly guru, but
the difference will only be a factor of 1-2 -- the algorithm is much more
important than the compilation, and this is where Clojure shines.

One other use is when a project is not performance-oriented, but development-
oriented. A fast development cycle is in a lot of situations much more
important than the speed at which the code runs. As Clojure is currently
limited to the JVM (and Javascript maybe??), extending this support to C now
extends the domain of Clojure to almost anything.

~~~
goggles99
A language from an entirely different paradigm (Functional language, Garbage
collection, tons of abstractions and a huge API) cannot ever be a replacement
for or even compete on the same playing field C. We are talking apples to
oranges here.

These languages are not comparable equivalents. Their specialties are
completely opposite. To make their output equivalent, you would have to
construct an AI system more advanced than anything that exists today.

~~~
Turing_Machine
"To make their output equivalent, you would have to construct an AI system
more advanced than anything that exists today."

Umm......

<http://en.wikipedia.org/wiki/Universal_Turing_machine>

------
goggles99
This IMO is an example of using the wrong tool for the job.

Closure is awesome and has it's place, C is the industry standard for
performance and also has it's place. The lines will never be crossed between
these two languages.

You are trying to fit a square peg in a round hole. If you improve your skills
from this project - great, but please don't try to mislead anyone that this is
a viable replacement for C (be up front about this).

A language from an entirely different paradigm (Functional language, Garbage
collection, tons of abstractions and a huge API) cannot ever be a replacement
for or even compete on the same playing field C. We are talking apples to
oranges here.

------
goggles99
Why do this? compile to native code directly if anything. Would you transform
it to C first so you could edit the C? Then what if you want to make a big
update using the Closure source? it will overwrite your changes.

This approach is not practical, perhaps I am failing to understand any logic
as to why you would go with this approach. Portability (between processor
architectures) is all I can think of but you will never achieve high
performance if this is the case.

C coders write their code differently against different processors because all
machines have different capabilities and resources (strength and weaknesses).

~~~
spacemanaki
Compiling to C is not at all an uncommon strategy, there's at least one pretty
serious Scheme implementation [1] that does this. Portability between
architectures is a pretty big advantage, but in this case another one is
leveraging the Boehm GC, rather than rolling your own. Could you use the Boehm
GC if you emitted assembly? I would guess maybe it's possible, but you'd have
to emit assembly that followed C calling conventions, I would imagine.
Emitting C might be easier. Lisp in Small Pieces has a pretty big chapter that
goes into detail how to compile Lisp to C.

[1]
[http://dynamo.iro.umontreal.ca/~gambit/wiki/index.php/Main_P...](http://dynamo.iro.umontreal.ca/~gambit/wiki/index.php/Main_Page)

see also:

[http://www.iro.umontreal.ca/~boucherd/mslug/meetings/2004102...](http://www.iro.umontreal.ca/~boucherd/mslug/meetings/20041020/90-min-
scc/90-min-scc.pdf)

[http://www.iro.umontreal.ca/~boucherd/mslug/meetings/2004102...](http://www.iro.umontreal.ca/~boucherd/mslug/meetings/20041020/minutes-
en.html)

~~~
takeoutweight
in clojure-scheme I actually compile Clojure to Gambit to make use of Gambit's
awesome runtime. It's a very good match for Clojure.

<https://github.com/takeoutweight/clojure-scheme>

