Hi Atamert,

Here's a gist with the example code: 
https://gist.github.com/neapel/4e502a14e3738b709672
I tried replacing a closure with a dynamically built and evaluated 
>> metafunction but discovered that it was actually slower.
>>
>
> If evaluating code during run is slower than AOT compiling it, it wouldn't 
> surprise me.
>

I didn't actually try AOT compiling it, just using the REPL. As far as I 
understand there shouldn't be a difference in speed, since (eval) runs the 
same compiler as AOT does, and even writes out a .class file.

(possibly unrelated, maybe due to eval, when trying to AOT compile the 
example project by adding `:aot :all` and running `lein jar`, it appears to 
fall into an infinite loop. The JAR file grew to 8GB, but I couldn't list 
its contents.)
 

> I guess f2 runs this much slower than f1 because it doesn't actually pass 
>> a reference to x when unquoting, but clones the value, which means it needs 
>> to compare the lists element-wise.
>>
>
> This is interesting. Were you able to confirm it or are you just guessing? 
> (I'm just curious.) 
>

 The code in the Gist produces a nice table now, here's my result (I 
couldn't reproduce the case where f3 runs as fast as f1 for vectors; but 
it's actually less weird this way)
I think it's quite obvious that f1 compares always references, as does the 
"nil" case, while the "vec" and "map" cases compare by value:

|    map |    vec |  nil | name |
|--------+--------+------+------|
|   5 ns |   5 ns | 5 ns |   f1 |
| 558 ns | 134 ns | 6 ns |   f2 |
| 567 ns | 130 ns | 7 ns |   f3 |
| 561 ns | 117 ns | 7 ns |   f4 |

It also dumps the disassembly, we can see that:

f1-map == f1-vec == f1-nil (makes sense, as the reference to the value is 
passed in the constructor of the closure)
f2-map = f3-map, f2-vec = f3-vec, f2-nil = f3-nil (with renaming)
f4-map = f1, f4-vec = f1, f4-nil = f1 (with renaming)
f2-map = f2-vec, except for calling clojure.lang.RT.map / vector.

So there are only three versions of the actual bytecode:
- the closure f1/f4;
- f2 building a new object in its static constructor
- f2-nil using a null constant instead of a field containing null.

importantly, f1/f4 are identical:
public final class F extends clojure.lang.AFunction {
  /* ... static constructor getting clojure.core/= ... */
  Object x;
  public F(Object o) { x = o }
  public Object invoke( Object y ) {
    /*basically*/ return (bool (= x y))
  }
}

So why does f4 behave almost like f2/f3?!


Cheers,

-- 
pascal

-- 
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.

Reply via email to