"so closures can be, and are, used to implement very effective objects with multiple methods" I don't really believe this to be efficient. The linked text by Kiselyov implements the dispatch via Scheme's (case ...) expression. Efficient dynamic dispatch means one indirection through a vtable, so one load instruction more compared to a normal function call. Which compilers for functional languages can perform this opt…
Clojure. Clojure has a fairly interesting feature called reify: (defprotocol Foo (bar [this]) (baz [this])) (defn make-foo [a] (reify Foo (bar [this] a) (baz [this] a))) (dotimes [_ 10] (let [x (make-foo 'x)] (time (dotimes [_ 1e8] (bar x) (baz x)))) So 2 methods called 1 billion times only takes about ~500ms on my 2.66ghz i7 MacbookPro. (of course, Clojure prefers values+behaviors, aka objects, without mucking it up…
Objects vs closures
11–19 of 19 posts
Re: Objects vs closures
#12"so closures can be, and are, used to implement very effective objects with multiple methods" I don't really believe this to be efficient. The linked text by Kiselyov implements the dispatch via Scheme's (case ...) expression. Efficient dynamic dispatch means one indirection through a vtable, so one load instruction more compared to a normal function call. Which compilers for functional languages can perform this opt…
(define (error . args) #f)
(define (class x y z)
(lambda (d)
(case d ('x x) ('y y) ('z z) (else (error "Invalid slot ~a" d)))))
(define obj (class 'this 'is-a 'test))
(display (obj (read)))
(newline)
The Stalin scheme compiler, if I read the output correctly, makes a
separate type for 'x, 'y, and 'z. Then it does the dispatch using a
switch statement (in the c code) over the three symbol types. This seems
quite resonable to me; The C compiler will probably produce a jump table.Note that I was unable to get the compiler to produce dispatch code at all without dispatching on the result of READ.
Re: Objects vs closures
#13I've often wished that C# let me implement interfaces with anonymous classes. Since it doesn't, I get around it by creating AdHoc classes for interfaces that I use a lot.
For instance, if I have an interface Foo defined as:
interface Foo
{
string Bar(int x);
}
then I also create a corresponding class called AdHocFoo defined like so: class AdHocFoo : Foo
{
Func _bar;
public AdHocFoo(Func bar)
{
_bar = bar;
}
public string Bar(int x)
{
return _bar(x);
}
}
I've written a little program that creates these AdHoc class definitions from interfaces.Re: Objects vs closures
#14Re: Objects vs closures
#15"so closures can be, and are, used to implement very effective objects with multiple methods" I don't really believe this to be efficient. The linked text by Kiselyov implements the dispatch via Scheme's (case ...) expression. Efficient dynamic dispatch means one indirection through a vtable, so one load instruction more compared to a normal function call. Which compilers for functional languages can perform this opt…
Re: Objects vs closures
#16I like the koan in the end. Now if only one can hit me in the head such that I understand the duality of electricity and magnetism...
Feynman explains it nicely in his lectures on physics. The key is relativity. (Magnetism is a relativistic effect of electricity.) http://en.wikipedia.org/wiki/Classical_electromagnetism_and_... may be interesting. Especially the section "Relationship between electricity and magnetism".
Re: Objects vs closures
#17Earlier quoted context omitted.
Clojure. Clojure has a fairly interesting feature called reify: (defprotocol Foo (bar [this]) (baz [this])) (defn make-foo [a] (reify Foo (bar [this] a) (baz [this] a))) (dotimes [_ 10] (let [x (make-foo 'x)] (time (dotimes [_ 1e8] (bar x) (baz x)))) So 2 methods called 1 billion times only takes about ~500ms on my 2.66ghz i7 MacbookPro. (of course, Clojure prefers values+behaviors, aka objects, without mucking it up…
It seems very likely to me that the JVM is recognizing that "bar" and "baz" don't do anything and (after some warm-up) optimizing them away. Microbenchmarking JVM is hard.
Re: Objects vs closures
#18Earlier quoted context omitted.
Feynman explains it nicely in his lectures on physics. The key is relativity. (Magnetism is a relativistic effect of electricity.) http://en.wikipedia.org/wiki/Classical_electromagnetism_and_... may be interesting. Especially the section "Relationship between electricity and magnetism".
Can someone summarize how magnetism is a relativistic effect?
http://en.wikipedia.org/wiki/Classical_electromagnetism_and_...
The main thing is to consider how charge densities change as we switch reference frames. Because the lengths contract when we switch to a reference frame where things are in motion, we see higher charge densities (same charge per less length).
A simple demonstration: Say we have a charge neutral, current carrying wire. We model it as a bunch of positive charges staying still, and some negative ones moving. The positive and neutral balance, but there is still a current because only the negatives are moving. Now imagine we switch to a different reference frame, one where the negative charges aren't moving, but the positive one's are, we are flying along parallel to the current. Now the positive charges contract relativisticly, so the density of positive charges is now greater than the negatives, and hence the wire appears to be carrying a net charge.
Re: Objects vs closures
#19Earlier quoted context omitted.
It seems very likely to me that the JVM is recognizing that "bar" and "baz" don't do anything and (after some warm-up) optimizing them away. Microbenchmarking JVM is hard.
Not true. Timings are completely different if you take a method out. I'm not saying that the JVM is not doing any magic here - but here is a closure that gets method dispatch as fast as the host can provide.
For comparison, looping 1e8 times with two calls to empty functions in a static language takes ~639ms, gives me ~3ns per call. So, you can see why my first suspicion was that the JVM was doing something like just inlining the methods and avoiding the call altogether. Considering the differences in our reported numbers, you may have a newer JVM than me, and if it is beating simple CALL instructions, it must be inlining them or avoiding some of the looping.