On Saturday, 14 September 2013 01:04:16 UTC+8, tbc++ wrote:

> >> This would be better, IMHO, than forever accepting semantics that 
> prevent idiomatic code from ever being truly fast.
>
> You're going to have a hard time convincing people to give up some of 
> the dynamism of Clojure just for the sake of more performance. Especially 
> considering that many Clojure users are perfectly okay with boxed values, 
> let alone need floats or other primitives.
>

Let's be clear - I'm not asking anyone to give up on any dynamism. I am 
asking for an agreement that we want to allow high performance *options* in 
Clojure, so that we can at least match Scala/Java, for those use cases 
where people have genuine performance requirements. Some people don't care 
about performance enough for the distinction between float and double to 
matter. But others do.

I think we (as a community) should try to support both use cases. Clojure 
has the potential to be *both* dynamic and fast if we design it right.

It would be a shame if people in the community took a general stance that 
"performance is good enough for me, so we aren't interested in supporting 
further performance improvements". I'm sure that isn't what is intended, 
but it could appear like that to people who raise performance issues only 
to get challenged / told that they don't have a valid problem.
 

>
> But what you are describing creates a whole ton of new problems, problems 
> I don't see a good solution for. What you are describing would require the 
> recompilation of entire source trees when a inner function is modified. So 
> now we're in the Scala/Java land of recompile after every edit. Perhaps 
> there's a use-case for invoke dynamic here, but now you're talking about 
> breaking backwards compatibility for everyone not using Java 7+. 
>

I'm not suggesting "recompile everything after edit". I'm suggesting 
"lazily recompile stuff that is dependent on the one thing you changed". 
That's a much smaller compilation unit in most cases - maybe you are 
recompiling 2-5 functions instead of 1. If you change something that is 
used everywhere in your whole app, then yes: maybe it's going to recompile 
100 or so functions. But even then, I doubt it will be a significant 
compile time compared to Java/Scala land.

And note that we're talking about incurring this cost only for people doing 
dynamic changes to existing vars. This isn't common production usage (if 
you are mutating production state, I would hope you are using something 
with proper concurrency semantics like atoms or agents or refs to mutate 
data!). So performance probably shouldn't matter at all, apart from the 
subjective experience of compiling fast enough to be usable at the REPL. 
Which I'm pretty sure is a fairly easy target to hit.
 
Like I said, this would be a big change, but it would be a good way to 
combine dynamism with excellent runtime performance.


>
> I'll be the first to admit that I'd like to rewrite the Clojure compiler 
> as a true multi-pass optimizing compiler. But that's a task I haven't 
> undertaken for two reasons 1) it's a ton of work that would take months (if 
> not years) to reach the level of performance currently offered by Clojure. 
> 2) I really don't need it. Every time I need that level of performance I 
> drop to Java, CUDA or some other high performance toolkit. 
>
> Personally I think it would be much better for someone to come up with a 
> typed lisp that interops very cleanly with Clojure. That way you can build 
> your inner kernels using a lisp-like language, and then glue it together 
> with Clojure.
>
> But let me close by saying, if you really want better primitives, I'd 
> suggest writing up a proposal for how it would work, perhaps even with some 
> example using macros and genclass. Until then we don't have anything to go 
> off of, people say "I'd love to have feature X", well we all would, but all 
> the suggestions thus far won't work, so how do you plan on fixing that?
>

My pragmatic proposal for now is very simple: allow metadata to specify 
functions to be compiled in a way that invocation is compiled statically to 
an invokevirtual. You lose the dynamic var deref, but gain better runtime 
performance and the ability to use arbitrary types / primitives (which 
solves the OP's problem).

This limited-scope proposal won't effect any existing dynamic usage, so 
people who like their fully mutable vars with their dynamic lookups can 
keep them.

It is on JIRA as CLJ-1263 , comments / improvements welcome.

http://dev.clojure.org/jira/browse/CLJ-1263


> Timothy
>
>
> On Fri, Sep 13, 2013 at 1:54 AM, Mikera <mike.r.an...@gmail.com<javascript:>
> > wrote:
>
>> On Friday, 13 September 2013 12:11:50 UTC+8, tbc++ wrote:
>>
>>> >> If we can do away with the interface generation, then support for 
>>> arbitrary primitive arguments should become relatively straightforward.
>>>
>>> How would we even call a function without an interface? Remember 
>>> everything is defined behind vars, so you simply can't assume that a 
>>> function won't be re-defed without notice. This is the reason interfaces 
>>> exist notice how the following works:
>>>
>>> user=> (defn foo ^long [^long x] x)
>>> #'user/foo
>>> user=> (defn baz [x] (foo x))
>>> #'user/baz
>>> user=> (baz 42)
>>> 42
>>> user=> (defn foo ^double [^double x] x)
>>> #'user/foo
>>> user=> (baz 42)
>>>
>>> ClassCastException user$foo cannot be cast to clojure.lang.IFn$LL 
>>>  user/baz (NO_SOURCE_FILE:1)
>>> user=>
>>>
>>
>> Good example to discuss!
>>
>> I agree there is a subtle tradeoff between performance and dynamism here.
>>
>> Any interface dispatch via a var uses an extra level of indirection (in 
>> the dynamic var case, this includes a thread-local check for any bindings) 
>> and already adds some overhead. If you are happy using Clojure's dynamic 
>> features to pass arbitrary (boxed / Object) arguments and redefine vars on 
>> the fly like that, you probably don't really care about optimal performance 
>> very much anyway and a standard IFn invoke should be OK. 
>>
>> For performance-sensitive code, you ideally want primitive-typed code to 
>> be compiled to a direct method call (invokevirtual) and not go via any var 
>> lookup / interface invoke at all. This would mean you would also need to 
>> redefine/recompile baz if you wanted to use a changed version of foo, but 
>> that's a relatively minor inconvenience IMHO. If you redefine baz after 
>> redefining foo (e.g. by reloading the whole namespace), then everything 
>> will still work. I'm not sure if it is possible to get this precise 
>> behaviour in Clojure at present - but it would certainly be great for high 
>> performance code.
>>
>> If we want *both* maximum performance and dynamic flexibility, then I 
>> think we need a completely different approach. Clojure vars as currently 
>> designed won't cut it. Probably something like an on-demand re-compilation 
>> strategy based on a var dependency graph would be needed. I personally 
>> think that's the right long-term direction, but that's definitely Clojure 
>> 2.0 territory.
>>  
>>
>>>
>>> Do a prototype with definterface/genclass or something and then report 
>>> your results. My suspicions are that you'll find doing this without 
>>> interfaces, while maintaining Clojure's semantics, is impossible.
>>>
>>
>> You may be right. Though it also probably depends on what you consider 
>> documented (promised not to change in public API) vs. undocumented 
>> (implementation detail) semantics. Some of the subtleties on what happens 
>> to existing code when you redefine vars are arguably in the latter 
>> category. Observe:
>>
>> (defn foo ^double [^double x] (inc x))
>> (defn baz [x] (foo x))
>> (baz 42)
>> => 43.0
>> (ns-unmap *ns* 'foo)
>> (defn foo ^double [^double x] (dec x))
>> (baz 42)
>> => 43.0
>>
>> i.e. it's fairly easy to trick Clojure into keeping an old version of a 
>> var around. Does that count as officially documented behaviour we are 
>> obliged to maintain?
>>
>> Either way, if Clojure's semantics prove to be a fundamental issue for 
>> performance, then I think it is better to start work to improve Clojure's 
>> semantics (perhaps targeting 2.0 if we think it's a really big breaking 
>> change). This would be better, IMHO, than forever accepting semantics that 
>> prevent idiomatic code from ever being truly fast. I'd rather see a bit of 
>> breakage and fix my code when upgrading to Clojure 2.0 than be stuck with 
>> poor performance forever.
>>
>>  
>>
>>>
>>> Timothy
>>>
>>>
>>> On Thu, Sep 12, 2013 at 8:41 PM, Mikera <mike.r.an...@gmail.com> wrote:
>>>
>>>> People *have* run into this problem a lot. People have just worked 
>>>> around it. The existence of great libraries like HipHip and vectorz-clj 
>>>> and 
>>>> some of Zach's stuff is IMHO to a large extent because people have needed 
>>>> high performance operations (often involving primitives / primitive arrays 
>>>> / custom JVM types) and have found it easier to implement these in a new 
>>>> library than wait for the support to appear in Clojure itself.
>>>>
>>>> So we have lots of great, performance-oriented libraries. Cool. 
>>>>
>>>> But not having comprehensive JVM primitive support is still a big 
>>>> problem for Clojure. It means that:
>>>> a) We'll get lots of ecosystem fragmentation as people with slightly 
>>>> different requirements implement their own solutions in slightly 
>>>> different/incompatible ways. We're seeing this already. Lisp Curse etc.....
>>>> b) People with very strong performance requirements on the JVM (e.g. 
>>>> OpenGL, big data numerics, scientific computing, heavy duty websites) are 
>>>> more likely to avoid Clojure and do their work in Scala / Java instead. 
>>>> The 
>>>> community will lose exactly the people who have both the motivation and 
>>>> skills to fix these kind of issues.
>>>> c) We won't get the wider reputation for performance that I think 
>>>> Clojure deserves and should aspire to. And this is important - rightly or 
>>>> wrongly, many people are attracted to languages with good performance 
>>>> credentials.
>>>>
>>>> I'd really love to be able to write everything in pure idiomatic 
>>>> Clojure and still guarantee great performance. Currently I can't, and in a 
>>>> large part this is due to JVM type-related issues like the following:
>>>> 1) Not all primitive types are fully supported as function args and 
>>>> return values (the issue raised in this thread)
>>>> 2) Lack of an efficient way to extend abstract base types (CLJ-1255 in 
>>>> Jira, for those interested)
>>>> 3) Lack of support for statically compiled reference types as function 
>>>> args (avoiding unnecessary instance checks and casting, CLJ-1256)
>>>> 4) The compiler still isn't very clever about using type inference to 
>>>> eliminate boxing / typecasts (perhaps CinC can help here?)
>>>>
>>>> Personally I'm less interested in floats (when I'm doing numerical 
>>>> stuff, double precision is usually more important), but I've certainly 
>>>> wanted ints many many times. I'm sure other people have wanted chars or 
>>>> bytes for various reasons (text processing? IO?). The point is that there 
>>>> are many valid reasons to use the primitive types on the JVM. I guess 
>>>> somebody even has a use for "short" somewhere...... ;-)
>>>>
>>>> Now let's get practical.
>>>>
>>>> What we need, I think, is some kind of "official" recognition that full 
>>>> JVM primitive support (i.e. all primitives supported in all situations) is 
>>>> an objective for Clojure in 1.6 or maybe 1.7. Then people can put in the 
>>>> time / effort to implement it. I'm personally very happy to help implement 
>>>> this myself providing that there is agreement that full primitive support 
>>>> is the way we want to go. Without official blessing, I'm unlikely to spend 
>>>> my weekends on speculative work that might not be accepted or appreciated. 
>>>> I suspect this is true for others too.
>>>>
>>>> If, on the other hand, the "official" answer is "Clojure will never 
>>>> support anything other than Objects, doubles and longs" then I'd want to 
>>>> know that too. I think that would be a *really* poor design decision 
>>>> because good compiled performance and good JVM interop ("embracing the 
>>>> host 
>>>> platform") seem to be two key principles of Clojure that have attracted 
>>>> many people. But hey, then I could at least save my weekends and focus on 
>>>> writing performance-oriented code in other languages (whether that is 
>>>> Java, 
>>>> Scala, pure bytecode, or some crazy new performance-oriented JVM Lisp). 
>>>>
>>>>
>>>> On Thursday, 12 September 2013 23:11:40 UTC+8, tbc++ wrote:
>>>>
>>>>> There are a combination of issues all contributing to the lack of 
>>>>> response on this subject. But before I continue let me state that these 
>>>>> opinions are my own. I have worked on Clojure and core.async, but these 
>>>>> comments are going to be personal conjecture and opinions:
>>>>>
>>>>> 1) As mentioned there is a high amount of complexity required to 
>>>>> implement all the interfaces needed for the different variants of 
>>>>> functions 
>>>>> you want. Primitive hinted functions currently implement Java interfaces, 
>>>>> implementing every combination of float, double, object, short, int, 
>>>>> long, 
>>>>> and byte for arities up to 5 would require the addition of over 16,000 
>>>>> interfaces. With the current config, we only need 81 interfaces. I'm not 
>>>>> saying this couldn't be changed to happen on-the-fly, it would just take 
>>>>> some serious work, and would cause problems with Java Interop 
>>>>>
>>>>> 2) The current system works, there are production databases (see 
>>>>> Datomic), neural networks (see the work by Prismatic), and many high 
>>>>> performance libraries (Zach Tellman has a reputation for bending Clojure 
>>>>> to 
>>>>> his will in this area), all written in Clojure. 
>>>>>
>>>>> 3) Because of #2, some may even go so far as to say that we should 
>>>>> drop everything but longs and doubles. Other dynamic languages (Python 
>>>>> for 
>>>>> instance) do this without problems, they simply relegate all the high 
>>>>> performance stuff to highly optimized libraries. This is what Prismatic 
>>>>> did 
>>>>> with HipHop (http://blog.getprismatic.com/****
>>>>> blog/2013/7/10/introducing-**hip**hip-array-fast-and-**flexible-**
>>>>> numerical-**computation-in-**clojure<http://blog.getprismatic.com/blog/2013/7/10/introducing-hiphip-array-fast-and-flexible-numerical-computation-in-clojure>
>>>>> ).
>>>>>
>>>>> 4) Writing small functional libraries in Java that interop with 
>>>>> Clojure is actually quite nice. So perhaps the answer is to build the 
>>>>> inner 
>>>>> kernels of your system in Java and then wrap them? I know that doesn't 
>>>>> sound fun, but you won't get much faster code than that. 
>>>>>
>>>>> So all the above make me sit back and say "what is it about your 
>>>>> problem that is unique and really requires floats? Why haven't we had 
>>>>> problems like this in the past."
>>>>>
>>>>> 5) And I think the problem really comes down to your API and target 
>>>>> platform (GPU). See, most of us would just typehint to doubles and take 
>>>>> the 
>>>>> memory hit. Doubles are fast on modern CPUs and memory is cheap. Not so 
>>>>> in 
>>>>> your case, as you mentioned you have concerns about memory size and 
>>>>> performance of certain primitives. 
>>>>>
>>>>> My conclusion is that you'd probably be best looking at the HipHop 
>>>>> library, and figuring out how you can adapt their ideas to your own code. 
>>>>> That is, write a small Java library that contains all the kernel code you 
>>>>> need, and then stitch together these primitives with Clojure. 
>>>>>
>>>>> As it stands, Clojure's support for type hinting floats is poor, but 
>>>>> that's not likely to change soon.
>>>>>
>>>>> ----
>>>>>
>>>>> TL;DR - The reason you haven't heard back is because no one has a good 
>>>>> answer as to how to fix it, or if it even needs to be fixed. That's not 
>>>>> the 
>>>>> answer anyone likes to hear, but I'm afraid that's the truth. Anyone else 
>>>>> on this list can feel free to correct me.
>>>>>
>>>>> Timothy Baldridge
>>>>>
>>>>>
>>>>> On Thu, Sep 12, 2013 at 8:38 AM, Alex Fowler <alex.m...@gmail.com>wrote:
>>>>>
>>>>>>
>>>>>> Does somebody from the development team read this user group? Or 
>>>>>> maybe I have addressed my questions to a wrong place?
>>>>>>  
>>>>>> -- 
>>>>>> -- 
>>>>>> You received this message because you are subscribed to the Google
>>>>>> Groups "Clojure" group.
>>>>>> To post to this group, send email to clo...@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+u...@**googlegroups.com
>>>>>>
>>>>>> For more options, visit this group at
>>>>>> http://groups.google.com/**group**/clojure?hl=en<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+u...@**googlegroups.com.
>>>>>>
>>>>>> For more options, visit 
>>>>>> https://groups.google.com/**grou**ps/opt_out<https://groups.google.com/groups/opt_out>
>>>>>> .
>>>>>>
>>>>>
>>>>>
>>>>>
>>>>> -- 
>>>>> “One of the main causes of the fall of the Roman Empire was 
>>>>> that–lacking zero–they had no way to indicate successful termination of 
>>>>> their C programs.”
>>>>> (Robert Firth) 
>>>>>
>>>>  -- 
>>>> -- 
>>>> You received this message because you are subscribed to the Google
>>>> Groups "Clojure" group.
>>>> To post to this group, send email to clo...@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+u...@**googlegroups.com
>>>> For more options, visit this group at
>>>> http://groups.google.com/**group/clojure?hl=en<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+u...@**googlegroups.com.
>>>> For more options, visit 
>>>> https://groups.google.com/**groups/opt_out<https://groups.google.com/groups/opt_out>
>>>> .
>>>>
>>>
>>>
>>>
>>> -- 
>>> “One of the main causes of the fall of the Roman Empire was that–lacking 
>>> zero–they had no way to indicate successful termination of their C 
>>> programs.”
>>> (Robert Firth) 
>>>
>>  -- 
>> -- 
>> You received this message because you are subscribed to the Google
>> Groups "Clojure" group.
>> To post to this group, send email to clo...@googlegroups.com<javascript:>
>> Note that posts from new members are moderated - please be patient with 
>> your first post.
>> To unsubscribe from this group, send email to
>> clojure+u...@googlegroups.com <javascript:>
>> 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+u...@googlegroups.com <javascript:>.
>> For more options, visit https://groups.google.com/groups/opt_out.
>>
>
>
>
> -- 
> “One of the main causes of the fall of the Roman Empire was that–lacking 
> zero–they had no way to indicate successful termination of their C 
> programs.”
> (Robert Firth) 
>

-- 
-- 
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/groups/opt_out.

Reply via email to