Re: Understanding when compilation occurs - for function producing functions

2014-06-22 Thread Mark P



 ​Well, you misunderstand it, as far as I know, clojure treat all fn as 
 object, so in your adder-maker example, clojure compiled two fn as object, 
 that's adder-maker itself and anonymous function it returns.


You must be right.  As far as I know, the compiler is only called as part 
of eval, and I don't think eval would be called every time a function wants 
to produce a resultant function at run time.

I guess what I'm trying to understand then, is how the maker function can 
produce a compiled function object when it doesn't know all the details of 
the function until runtime (the m parameter in this case).
 

 The compiled add-maker is just instantiate that anonymous with `m`, and 
 return it. So (adder-maker 1) will produce that instantiated anonymous 
 function, and since it's a function and it's in the first position of list, 
 clojure will invoke it with 2, and that anonymous function will do actual 
 computation.


So maybe what is happening underneath is...  When the function maker 
function is compiled, it creates a java object type corresponding to the 
anonymous function.  This object type includes both an invocation member 
(taking one argument, n) and storage for m.  Then at run time when this 
function is needed for a particular m (in this case 1), an instance of the 
java object type is created, with m set to 1.

That's what I am guessing anyway.

What this does mean though I guess is that the code can't be optimized to 
take advantage of the specific case of m being 1 (eg low level using an inc 
instruction on n rather than explicitly adding 1 to it).

But maybe this is where JIT optimization comes into play - maybe this 
optimization can happen here?

Thanks for your reply.

Cheers,

Mark.

P.S. I still wonder whether the clojure compiler itself could do some kind 
of mini-compile when at-runtime producing a function.  I guess it would be 
hard for the compiler to know whether the mini-compile was warranted or not.
 


 functions are compiled at once when clojure reader meet them, and 
 invocation is just the matter of instantiate.

 Thanks,
 Di Xu


-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Understanding when compilation occurs - for function producing functions

2014-06-22 Thread Mark P



 What's the reason for asking? If you aim for making efficient code (that 
 is running very many times in tight loops), I think most of this will be 
 inlined by the JIT, as long as it is not confused by side effects and other 
 things.


I'm asking mostly because I want to better understand the essence of how 
clojure works.  But you are right in thinking that I am also interested in 
better understanding performance implications - but this is a secondary 
reason.  Primarily, I'm just trying to understand better.

Coming from a C++ background I'm not that familiar with functions as first 
class values.  We sort of do have them in C++ - as functors - ie a class 
that has the function invocation operator defined.  This class can have 
storage as well, which means you can have a functor object type which then 
can have particular instances instantiated with different particular 
parameters stored with the object instance.

I'm wondering whether this is effectively what Clojure does under-the-hood, 
or whether it does something different / more sophisticated.
 


 As long as the JVM can optimize the procedure, it's of lesser importance 
 how Clojure solves it in one-shot scenarios.


In one sense yes, though it's nice to better understand what is happening 
and how this influences program performance.
 


 Maybe I somewhat dodge the question, but dynamic just in time compilation 
 is so mindblowing cool that an hypothesis about the quickest possible way 
 to solve the problem combined with profiling is what matters most in 
 practice.

 /Linus


-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Understanding when compilation occurs - for function producing functions

2014-06-22 Thread Mark P


 A toy project I've worked intermittently on makes heavy use of *partial* 
 to dynamically build complex functions.  I wish that *partial* was smart 
 enough to recompile its first argument, maybe taking advantage of whatever 
 type inference the compiler can make, but partial 
 https://github.com/clojure/clojure/blob/028af0e0b271aa558ea44780e5d951f4932c7842/src/clj/clojure/core.clj#L2460
  
 only returns a function wrapper.  Ohwell.


This raises a different question with me...  Does clojure have the same 
scope for code optimization that other languages, eg C++, have?  Ie, even 
though a C++ compiler has to deal with all sorts of complicated syntax, it 
is able to perform a whole lot of at-compile-time optimizations based on 
the C++ semantics.  Is the clojure compiler free to do a similar thing?  Or 
is it bound to adhere to the straightforward evaluation rules?

My understanding is that one of the roles of macros is to perform 
at-compile-time optimizations.  Sometimes a macro can do something clever 
to transform less performant code into optimized code.  But is this the 
only way of improving compiled code - ie introducing code-optimizing macros 
- or does the clojure compiler itself have scope to elide certain things 
and make other performance optimizations?

I know the java JIT optimization reduces the need for this, but my guess is 
that there is still a role for at-compile-time code optimization.

Cheers,

Mark.

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Understanding when compilation occurs - for function producing functions

2014-06-22 Thread Reid McKenzie

 Coming from a C++ background I'm not that familiar with functions as
 first class values.  We sort of do have them in C++ - as functors - ie
 a class that has the function invocation operator defined.  This class
 can have storage as well, which means you can have a functor object
 type which then can have particular instances instantiated with
 different particular parameters stored with the object instance.

 I'm wondering whether this is effectively what Clojure does
 under-the-hood, or whether it does something different / more
 sophisticated.

Okay. Functions as values. Go look at the IFn interface,
https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/IFn.java.
In C or C++ you can take a raw machine pointer to a function. The JVM
does not allow for this behavior the result of which is that whenever
you have a function really what you have is a function-like object
with the standard application/invocation member methods. Nothing really
sophisticated here, a single class is naively generated for each fn in
your program and a fn that returns a fn simply creates a new instance of
that fn and returns it since there's no other way that we can take a
function as a value prior to JVM 1.8 which has bytecode lambdas and
which the reference Clojure implementation doesn't leverage yet if ever.

The standard Clojure compiler is pretty braindead when it comes to the
emitted bytecode, but this is due to the philosophy (backed up by
experience) that the JIT is typically good enough. You could generate
better code, and my GSoC project is research into doing so but the
reality of Clojure programs is that function calls even with Var
indirection are free in comparison to the performance hits we take due
to using immutable datastructures and eschewing in place updates.

Reid

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Understanding when compilation occurs - for function producing functions

2014-06-22 Thread Herwig Hochleitner
2014-06-22 9:12 GMT+02:00 Reid McKenzie rmckenzi...@gmail.com:


 since there's no other way that we can take a
 function as a value prior to JVM 1.8 which has bytecode lambdas and
 which the reference Clojure implementation doesn't leverage yet if ever.


Java 8 gained no such feature. Lambda expressions are syntax sugar for
almost the thing, clojure's fn does: Instantiating an anonymous inner class
for an interface with a single arity.
The only concept that jvm has of a first class function, are the interfaces
in java.util.function, as of Java 8
Sorry for the nitpick!

Concerning more extensive compiler optimizations: The simplistic approach
of the compiler has the benefit of generating pretty predictable byte code,
which is good for a lot of cases, as long as the JIT can optimize it and as
long as you don't need fast startup.
The JIT can do pretty amazing stuff like inlining heap allocations onto the
stack, if they don't escape. So in theory that could eliminate lazy-seqs,
partial functions and other wrappers.

I'd also like to see more extensive optimization by the clojure compiler,
but I wouldn't pass the burden of implementing them onto anyone, before
clojure.tools.{analyzer,emitter} are used as the canonical compiler.

cheers

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Understanding when compilation occurs - for function producing functions

2014-06-22 Thread Mark P


 Okay. Functions as values. Go look at the IFn interface, 

 https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/IFn.java. 



Thanks for the link - this helps!  When the clojure compiler generates a 
class type that conforms to this interface, does it generate a .java file 
which is then compiled using the java compiler?  I am guessing not.  I am 
guessing that clojure knows how to generate a byte code version of a class 
type directly.
 

 In C or C++ you can take a raw machine pointer to a function. The JVM 
 does not allow for this behavior the result of which is that whenever 
 you have a function really what you have is a function-like object 
 with the standard application/invocation member methods.


Thanks for explaining.  This sounds very much like a C++ functor.

For the record, the raw-pointer-to-function is the old-school thing to do 
in C++.  These days functors are often used - object types that have the 
function application operator defined (which is a method with special 
function application syntax) - because these are more powerful (eg 
templated methods allowing compile-time polymorphism) and allow for better 
performance (eg inlining of code).  So it sounds like what clojure does 
under-the-hood is to more-or-less define a functor type at compile time and 
then do various instantiations at run time.
 

 The standard Clojure compiler is pretty braindead when it comes to the 
 emitted bytecode, but this is due to the philosophy (backed up by 
 experience) that the JIT is typically good enough.


Good to know - thanks!  This makes things clearer for me.
 

 You could generate 
 better code, and my GSoC project is research into doing so but the 
 reality of Clojure programs is that function calls even with Var 
 indirection are free in comparison to the performance hits we take due 
 to using immutable datastructures and eschewing in place updates. 

 Reid  


-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Understanding when compilation occurs - for function producing functions

2014-06-22 Thread Ryan Schmitt


 Okay. Functions as values. Go look at the IFn interface, 

 https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/IFn.java.
  



 Thanks for the link - this helps!  When the clojure compiler generates a 
 class type that conforms to this interface, does it generate a .java file 
 which is then compiled using the java compiler?  I am guessing not.  I am 
 guessing that clojure knows how to generate a byte code version of a class 
 type directly.


The Clojure compiler generates .class files and Java bytecode directly, 
using the ASM http://asm.ow2.org/index.html library. Note that Clojure 
code is always compiled to Java bytecode, even in the REPL; Clojure is 
never directly interpreted. There are some good resources on how Clojure 
compilation works:

http://clojure.org/compilation
http://www.deepbluelambda.org/programming/clojure/how-clojure-works-a-simple-namespace
 
(namespaces also get compiled to Java classes, which is a bit less 
intuitive)
http://stackoverflow.com/questions/3123662/compiling-clojure (if you want 
to play around with invoking the Clojure compiler directly)

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Understanding when compilation occurs - for function producing functions

2014-06-22 Thread Alex Miller


On Sunday, June 22, 2014 11:35:25 AM UTC-5, Herwig Hochleitner wrote:

 2014-06-22 9:12 GMT+02:00 Reid McKenzie rmcke...@gmail.com javascript:
 :


 since there's no other way that we can take a
 function as a value prior to JVM 1.8 which has bytecode lambdas and
 which the reference Clojure implementation doesn't leverage yet if ever.


 Java 8 gained no such feature. Lambda expressions are syntax sugar for 
 almost the thing, clojure's fn does: Instantiating an anonymous inner class 
 for an interface with a single arity.
 The only concept that jvm has of a first class function, are the 
 interfaces in java.util.function, as of Java 8


I think (but would be happy to be corrected) that Java 8 lambdas *are* 
actually a little different than an anonymous class instantiation. 
Specifically, I believe the lambda is created via an invokeDynamic and 
cached at the call site, whereas the anonymous class instance would be 
constructed every time.

Alex

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Understanding when compilation occurs - for function producing functions

2014-06-21 Thread Di Xu

 Suppose at my REPL I do...

 (defn direct-report-oneplustwo [] (println (str Direct one plus two is 
 ((fn [n] (+ 1 n)) 2) .)))

 ...then I presume that the compiler has compiled my
 direct-report-oneplustwo function, and that this has included compilation
 of my anonymous function (fn [n] (+ 1 n)).  So that now if I run...

 (direct-report-oneplustwo)

 ...at my REPL it just needs to run this precompiled code to tell me my
 answer 3 - no additional compilation required.

 So far so good.

 But what if instead I do this at my REPL...

 (defn adder-make [m] (fn [n] (+ m n)))

 (defn indirect-report-oneplustwo [] (println (str Indirect one plus two
 is  ((adder-make 1) 2) .)))

 ...Now at this point, both adder-make and indirect-report-oneplustwo
 should have been compiled.  But unlike our first approach, the anonymous
 function (fn [n] (+ 1 n)) has not yet been created by (adder-make 1) and so
 presumably (??) has not yet been compiled??

 I am presuming that it is only when we actually run the report function...

 (indirect-report-oneplustwo)

 ...that (adder-make 1) is actually run, thereby producing the anonymous
 function (fn [n] (+ 1 n)), which then gets compiled right then-and-there,
 immediately followed by its execution??


​Well, you misunderstand it, as far as I know, clojure treat all fn as
object, so in your adder-maker example, clojure compiled two fn as object,
that's adder-maker itself and anonymous function it returns.

The compiled add-maker is just instantiate that anonymous with `m`, and
return it. So (adder-maker 1) will produce that instantiated anonymous
function, and since it's a function and it's in the first position of list,
clojure will invoke it with 2, and that anonymous function will do actual
computation.

functions are compiled at once when clojure reader meet them, and
invocation is just the matter of instantiate.

Thanks,
Di Xu

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Understanding when compilation occurs - for function producing functions

2014-06-21 Thread Linus Ericsson
On Saturday, June 21, 2014, Di Xu xudi...@gmail.com wrote:

 Suppose at my REPL I do...

 (defn direct-report-oneplustwo [] (println (str Direct one plus two is 
 ((fn [n] (+ 1 n)) 2) .)))

 ...then I presume that the compiler has compiled my
 direct-report-oneplustwo function, and that this has included compilation
 of my anonymous function (fn [n] (+ 1 n)).  So that now if I run...

 (direct-report-oneplustwo)

 ...at my REPL it just needs to run this precompiled code to tell me my
 answer 3 - no additional compilation required.

 So far so good.

 But what if instead I do this at my REPL...

 (defn adder-make [m] (fn [n] (+ m n)))

 (defn indirect-report-oneplustwo [] (println (str Indirect one plus two
 is  ((adder-make 1) 2) .)))

 ...Now at this point, both adder-make and indirect-report-oneplustwo
 should have been compiled.  But unlike our first approach, the anonymous
 function (fn [n] (+ 1 n)) has not yet been created by (adder-make 1) and so
 presumably (??) has not yet been compiled??

 I am presuming that it is only when we actually run the report function...

 (indirect-report-oneplustwo)

 ...that (adder-make 1) is actually run, thereby producing the anonymous
 function (fn [n] (+ 1 n)), which then gets compiled right then-and-there,
 immediately followed by its execution??


 ​Well, you misunderstand it, as far as I know, clojure treat all fn as
 object, so in your adder-maker example, clojure compiled two fn as object,
 that's adder-maker itself and anonymous function it returns.

 The compiled add-maker is just instantiate that anonymous with `m`, and
 return it. So (adder-maker 1) will produce that instantiated anonymous
 function, and since it's a function and it's in the first position of list,
 clojure will invoke it with 2, and that anonymous function will do actual
 computation.

 functions are compiled at once when clojure reader meet them, and
 invocation is just the matter of instantiate.

 Thanks,
 Di Xu


What's the reason for asking? If you aim for making efficient code (that is
running very many times in tight loops), I think most of this will be
inlined by the JIT, as long as it is not confused by side effects and other
things.

As long as the JVM can optimize the procedure, it's of lesser importance
how Clojure solves it in one-shot scenarios.

Maybe I somewhat dodge the question, but dynamic just in time compilation
is so mindblowing cool that an hypothesis about the quickest possible way
to solve the problem combined with profiling is what matters most in
practice.

/Linus

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Understanding when compilation occurs - for function producing functions

2014-06-21 Thread David Andrews
A toy project I've worked intermittently on makes heavy use of *partial* to 
dynamically build complex functions.  I wish that *partial* was smart 
enough to recompile its first argument, maybe taking advantage of whatever 
type inference the compiler can make, but partial 
https://github.com/clojure/clojure/blob/028af0e0b271aa558ea44780e5d951f4932c7842/src/clj/clojure/core.clj#L2460
 
only returns a function wrapper.  Ohwell.

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.