> >> fft1976 wrote:
> >>> Java: 1.5x slower than C as a rule of thumb.
> >> I think it can achieve parity.
>
> > I disagree. I don't think the JIT can do much about the memory layout
> > of the data structures. Compare a vector of complex numbers or of 3D
> > vectors (NOT of pointers to them) in C/C++ and Java. Run some tests. I
> > did and I looked at others'.
>
> > For me, 1.5x is a good trade-off for safety though.
>
> The JIT can't, but the coder can. If you want a vector of N
> double-precision complex numbers in Java that is contiguous in memory,
> for example, you could use a Java array of 2xN doubles and index into it
> appropriately.
This is fanboy fantasy, not reality. If I have a library for dealing
with 3D vectors, I'm not going to lay out my data in flat arrays and
copy the vectors back and forth. Also, this trick won't work with non-
homogeneous records.
> >> With Java, in most cases you can slap "implements Cloneable" on a
> >> class and make the clone method public,
>
> > Java's "clone" does a shallow copy only (check the docs).
>
> True. If you want a deep copy you will have to implement it yourself.
That's what I wrote. What was the point of your comment?
> Or
> you can make a deepCopy static utility method that exploits
> "Serializable" to deep copy anything that's serializable simply by
> serializing and deserializing it (which can use memory, or a temp file,
> and not much memory if you make an auxiliary class implement both
> InputStream and OutputStream, with its OutputStream methods writing to a
> growable buffer and its InputStream methods consuming (possibly blocking
> if necessary) from same. Closing the OutputStream aspect EOFs the
> InputStream aspect. Then wrap in ObjectInput/OutputStream. You can use a
> BlockingQueue of byte arrays of length 8192 (or whatever), serialize to
> one end and deserialize from the other in concurrent threads, and it
> will tend to not use much memory. Limit the BlockingQueue length to 1
> item and it will never use much more than 8Kbyte (the OutputStream
> aspect will block until the InputStream aspect consumes from the queue).
Ouch...
> If the bulk of the time is spent performing arithmetic operations on
> just a few values,
We are talking number crunching here, not useless pissing contests,
like calculating the digits of Pi.
> If the arithmetic is bignum, the bulk of your time will be spent
> performing individual bignum operations.
Contrary to what the term sounds like, number crunching is rarely
about bignums.
> If the arithmetic is on smallnums in arrays and the computations are
> mostly mutations, then you may want to use Java arrays,
That's what I said.
> In practice,
> Clojure access to Java arrays, even primitive arrays, seems to
> be slow. This may be addressed in a future version.
Yeah, yeah...
I noticed that you decided to delete this, by the way:
In practice, experts seem to
agree that Clojure is 5-10 times slower than Java:
http://groups.google.com/group/clojure/msg/92b33476c0507478
(relevant follow-up set)
Agreed. I can confirm that C++ is much better for my kind of number
chrunching tasks. I have to solve big nonlinear optimization problems
and switched from Java to C++ two years ago. I'm not looking back. The
ability to write user-defined types that are handled like builtin
types (no indirection, no heap allocations) combined with "true
genericity" is key.
> > In practice,
> > Clojure access to Java arrays, even primitive arrays, seems to
> > be slow. This may be addressed in a future version.
Are we talking about the language "Clojure" (lisp dialect) or the
cloSure proposal for Java 7?
Cheers!
SG
Stop attacking me. I have done nothing to deserve your repeated flamage.
You must have the wrong target. Recheck and then go flame the correct
target.
> If I have a library for dealing with 3D vectors, I'm not going to lay
> out my data in flat arrays and copy the vectors back and forth.
If you have a library for dealing with X, in any language, you'll use
the data as laid out by that library.
A performant Java library for numerics should lay out its data in an
appropriate manner so as to achieve performance, of course.
> Also, this trick won't work with non-homogeneous records.
It will work for records of a primitive type, such as double. It won't
work if for some odd reason you want to mix ints and doubles in the same
vector, no. In that unusual case you may be better off either using
multiple separate arrays, but allocated one right after the other so
probably close together, one with all the ints and one with all the
doubles, or else resorting to JNI to implement some things.
>>>> With Java, in most cases you can slap "implements Cloneable" on a
>>>> class and make the clone method public,
>>> Java's "clone" does a shallow copy only (check the docs).
>> True. If you want a deep copy you will have to implement it yourself.
>
>> Or
>> you can make a deepCopy static utility method that exploits
>> "Serializable" to deep copy anything that's serializable simply by
>> serializing and deserializing it (which can use memory, or a temp file,
>> and not much memory if you make an auxiliary class implement both
>> InputStream and OutputStream, with its OutputStream methods writing to a
>> growable buffer and its InputStream methods consuming (possibly blocking
>> if necessary) from same. Closing the OutputStream aspect EOFs the
>> InputStream aspect. Then wrap in ObjectInput/OutputStream. You can use a
>> BlockingQueue of byte arrays of length 8192 (or whatever), serialize to
>> one end and deserialize from the other in concurrent threads, and it
>> will tend to not use much memory. Limit the BlockingQueue length to 1
>> item and it will never use much more than 8Kbyte (the OutputStream
>> aspect will block until the InputStream aspect consumes from the queue).
>
> Ouch...
No ouch. You'd only have to do this once, and then deepCopy would work
on every serializable type in Java, including ones that didn't exist
when you wrote deepCopy.
>> If the bulk of the time is spent performing arithmetic operations on
>> just a few values,
>
> We are talking number crunching here
Yes, I know.
>> If the arithmetic is bignum, the bulk of your time will be spent
>> performing individual bignum operations.
>
> Contrary to what the term sounds like, number crunching is rarely
> about bignums.
I never said otherwise.
>> If the arithmetic is on smallnums in arrays and the computations are
>> mostly mutations, then you may want to use Java arrays,
>
> That's what I said.
Now that the debate is over, please respect the followup-to header.
It would have been better, of course, had you chose to end it *before*
demonstrating to the entire world that you're unimaginative and
ignorant. Ignorant of numerous performance tricks for Java and other JVM
languages, ignorant of performant functional algorithms for various
things, and ignorant of the actual facts from timing operations, which
show all three languages capable of achieving the same top speed in
numeric calculations. And unimaginative enough not only to be unable to
think up any of these things, but also unable to think up arguments that
aren't laced heavily with ad hominems and other rhetoric. "This is
fanboy fantasy, not reality," "What was the point of your comment?,"
"Ouch...," "We are talking number crunching here, not useless pissing
contests," "Yeah, yeah...," and so forth do not constitute rational
arguments.
The former.
And since you clearly didn't even know what "Clojure" was referring to,
your claims that C++ is necessarily "much better" ring hollow.
In fact, Clojure, having macros and access to Java arrays, is capable of
working with contiguous blocks of doubles or similarly and treating
them as structured into discrete complex numbers, vectors, or
what-have-you, and is capable of "true genericity". Lisps in general are
much more capable of "true genericity" than C++ is.
Even Java can be made to perform at C-like speeds with suitable
structuring of your data; it's just that you can't always encapsulate
that data into discrete Java objects and keep that performance.
Although, objects allocated sequentially tend to be allocated at
close-together memory locations in Java, and the new G-1 garbage
collector should help further with keeping objects that are used
together close together in memory, improving locality of memory access
patterns.
Regardless, actual benchmark numbers show all three languages achieving
comparable speeds at comparable numerical tasks, IF the code in each
language is performance-tuned by someone reasonably expert in the use of
that language. Of course, when an ignoramus such as either of the
preceding posters, who clearly know only the bare bones about Java and
nothing at all about Clojure, attempt to write performant code in those
languages, they can expect to do poorly.
And of course, the savings from using a smart algorithm beat a
few-percent or even a few-tens-of-percent difference in raw execution
speed anyday.
(defn fib[n]
(nth (map second (iterate (fn [[a b]] [b (+ a b)]) [0 1])) n))
in clojure will be hugely faster than
int fib (int n) {
if (n == 0 || n == 1) return 1;
return fib(n - 1) + fib(n - 2);
}
anyday. (And won't wrap after 1836311903, or, worse, after 28657, either.)
Everyone who decides to reply to this joker, watch out: he's silently
adding "Followup-To: alt.olympics" to his messages, trying to trick
you into not posting here, so he would have the last word.
Is this what Clojure fanboys must resort to when they lose an
argument? I thought Haskell and Common Lisp had the worst fanboys till
today.
No, I am not. I am adding a followup-to for atl.olympics. (Note spelling.)
It's currently an empty newsgroup, so it seemed appropriate as a place
to redirect your useless and illogical flamage.
> Is this what Clojure fanboys must resort to when they lose an
> argument?
I wouldn't know, since that's never happened to me.
fft1976 is the one who "silently" decided to drag this flamewar into
clj.programmer. We were doing just fine without it.
f/u set to comp.programming and please keep your flamewar out of clj groups.
--
Lew
Right. Writing such algorithms generically incurs huge performance
degradation in Java and Clojure.
>> > For me, 1.5x is a good trade-off for safety though.
>>
>> The JIT can't, but the coder can. If you want a vector of N
>> double-precision complex numbers in Java that is contiguous in memory,
>> for example, you could use a Java array of 2xN doubles and index into it
>> appropriately.
That workaround sucks because you've either lost polymorphism or, if you
rewrite the entire compiler to use whole program optimizations and change
the calling convention globally, you've lost incremental compilation and
dynamic loading.
> This is fanboy fantasy, not reality.
Yes. Clojure has some nice features but its most serious deficiencies are
inherited from the JVM and there is nothing Clojure can do about it, e.g.
value types and TCO. Moreover, according to Sun employees on the JVM
languages group this is never likely to be fixed.
That is a major problem with all JVM-based languages in the context of
technical computing. Perhaps the best solution for technical users would be
for languages like Scala and Clojure to target MLVM instead of the JVM and
leverage its existing tail calls and then work towards getting value types
implemented as well.
--
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
Thanks for that very informative comment !
:-)
Arne
> > This is fanboy fantasy, not reality.
>
> Yes. Clojure has some nice features but its most serious deficiencies are
> inherited from the JVM and there is nothing Clojure can do about it, e.g.
> value types and TCO.
Not as far as speed is concerned, in practice. If you give up 1.5x
speed by going from C++ to Java, and 5-10 by going from Java to
Clojure [1], than the latter is much more relevant.
I actually think 1.5x is a good trade for memory safety, as I stated.
It's beyond me why this "jhar...@hatlop.de" fella decided to argue
about it, when he obviously knows nothing about number crunching. What
a nut case.
[1] http://groups.google.com/group/clojure/msg/92b33476c0507478
Flame war, flame war, flame war. Go on to comp.programming and have a great time.
--
Lew
I second this opinion. Statically typed UDT + templates and also
operator and function overloading are big wins for C++ numerical
work. Despite its faults, C++ provides an interesting and useful
mix of capabilities in my opinion and C++0x makes it even better.
KHD
Lack of value types can cost you a lot more than 1.5x though. Try writing an
FFT over boxed complexes and Java and compare with unboxed in C99, for
example.
> I actually think 1.5x is a good trade for memory safety, as I stated.
> It's beyond me why this "jhar...@hatlop.de" fella decided to argue
> about it, when he obviously knows nothing about number crunching. What
> a nut case.
This goes way beyond number crunching though. Lots of applications benefit
enormously from value types. They are used extensively in the .NET
framework.
If I remember correctly, Java3D has (had?) a version of many of its
primitives which operate on arrays.
Not that it was convenient to use.
FWIW, "inline" in F# provides the same benefits in an easier to use form. It
really rocks. :-)
Clojure has TCO; you just have to make your use of it explicit (and then
the compiler alerts you if it's not really in tail position).
I'm not sure what you mean by "value types". If you mean immutable types
with value-equality semantics remaining consistent over time, then
Clojure is chock full of them, even its collection types can be used as
value types, so as keys in maps for instance.
If you mean non-pointer types, Clojure has access to the full range of
Java non-pointer types: boolean, byte, short, int, long, float, double,
and char.
It can't currently pass them across function call boundaries without
boxing and unboxing, but you can work around that using definline or a
macro.
> This goes way beyond number crunching though. Lots of applications benefit
> enormously from value types. They are used extensively in the .NET
> framework.
The JVM has several non-pointer types too, and does not have the
Microsoft taint.
http://en.wikipedia.org/wiki/Value_type
Arne
Clojure has recur and trampolines, both of which are workarounds for the
lack of TCO.
> I'm not sure what you mean by "value types".
http://msdn.microsoft.com/en-us/library/s1ax56ch(VS.80).aspx
>> This goes way beyond number crunching though. Lots of applications
>> benefit enormously from value types. They are used extensively in the
>> .NET framework.
>
> The JVM has several non-pointer types too...
Value types are user-defined non-pointer types, i.e. structs. For example,
you can define a complex type as a struct of two doubles or a Vertex type
as a struct of three floats and three int16s.
In Clojure, you can workaround the lack of arrays of complex numbers using
arrays of floats and syntactic abstraction to fudge the difference
(Greenspunning instantiation-per-type generics which the JVM also lacks)
but you cannot work around the general case.
This incurs huge performance degradation for programs on the JVM and can
make direct interop impossible (e.g. the JVM cannot express XNA).
Post your code.
> Your "value types" are overrated anyway.
Look at vertices in XNA for a simple example where value types on .NET
facilitate efficient direct interop with the graphics hardware.
> If you want high-performance code you might want the high-performance
> parts not to make calls into Java, or else to be JNI calls, one or the
> other.
Sure.
> One example where Clojure will do just fine is when you want to do
> numerics and also present a nice user interface. The numerics code can
> be very fast (but may not use Java interop) while the GUI code only
> needs to be fast enough for the UI to feel responsive (and will use Java
> Swing methods and objects extensively). Your "deficiencies" may have
> "already damaged" the Swing code, but that's not the CPU-bound part of
> the system anyway.
Sure. There are certainly situations where this is not a problem.
>>>>> This is fanboy fantasy, not reality.
>>>>
>>>> Yes.
>>>
>>> Stop attacking me.
>>
>> I am not attacking you.
>
> Sure you are. I wrote truth, and in response to that I got dumped on
> with a steaming load of ad hominems.
Ad hominem means personal attack. I have said nothing about you.
>> Clojure offers trampolines to cover more general cases of indirect tail
>> calls between different functions but it is much slower than real tail
>> call elimination.
>
> Balderdash.
See the discussion here, for example:
http://lambda-the-ultimate.org/node/3106
For a practical application of tail call elimination, look at extensible
state machines.
>>> I'm not sure what you mean by "value types".
>>
>> http://msdn.microsoft.com/en-us/library/s1ax56ch.aspx
>
> I'm sorry, but I am asking you, not some web site (and especially not
> some Microsoft web site), what you mean. If you don't want to actually
> have a constructive dialog, feel free to STFU. Otherwise, actually say
> something.
Please familiarize yourself with the basic terminology by reading the
literature I have cited.
>>> If you mean non-pointer types, Clojure has access to the full range of
>>> Java non-pointer types: boolean, byte, short, int, long, float, double,
>>> and char.
>>
>> The ability to define custom value types is extremely valuable, most
>> notably in the context of technical computing where you want 32- and
>> 64-bit complex numbers, 2d vectors, 3d vectors in homogeneous
>> coordinates, quaternions and dozens of other types to be representable
>> without the overhead of boxing, heap allocating, stressing the garbage
>> collector and so on.
>
> First of all, I explained in previous posts that you can do that in
> Java, and with full data abstraction in Clojure.
No, this is impossible to do in any JVM-based language in Java. Consider an
array of structs that contain both ints and floats, for example. There is
no way to represent that on the JVM because you only have an array of ints
or an array of floats but not an array of structs composed of both ints and
floats.
> Second, if you define classes like Complex and Vect in Java with fields
> of type double, the doubles don't get individually boxed.
But the complex numbers and vectors do, which incurs massive performance
degradation.
> Third, the overhead of "heap allocating, stressing the garbage collector
> and so on" in a modern JVM is about the same as the overhead of stack
> allocating, on an amortized per-object basis: a pointer bump and
> whatever construction is done to write values to memory.
No, the performance difference is huge and stems from the cost of nursery
collection, particularly synchronization.
>>> It can't currently pass them across function call boundaries without
>>> boxing and unboxing, but a) if the function call is consistent, the JIT
>>> can inline it and optimize away the boxing and unboxing, and b) Clojure
>>> has macros, so it's possible to inline a function not being itself
>>> passed across function calls without losing the function-call syntax.
>>
>> Only if your code is written entirely in Clojure which will not be the
>> case
>
> Why won't it?
Because you will be calling library functions.
>> you are on the JVM to reuse existing Java libraries
>
> Laughable. You may be on the JVM to get portability, or a top-notch GC,
> or any combination of things. And if you are on the JVM to use existing
> Java libraries, that usage might not be in the numeric parts of the
> code...
Or it might be JLAPACK which has had its usability degraded due to the
fundamental limitations of the JVM (no efficient complex numbers forcing
separate incompatible APIs for everything that deals with complex numbers)
or it might be OpenGL which has had its performance degraded due to
fundamental limitations in the JVM (no value types to represent vertex
data).
> Last, but certainly not least, the Java libraries you're using might be
> existing high-performance numerics libraries for Java! Or Java wrappers
> around GMP or a similar native-code library.
The JVM is also extremely slow to invoke external code (an order of
magnitude slower than the CLR, for example) so those libraries also suffer
from limitations of the JVM. Again, this is unavoidable in Clojure.
>> but those libraries expose these deficiencies of the VM by providing
>> non-generic interfaces.
>
> A bit of Clojure magic could wrap these in much nicer interfaces even so
> -- and, using macros or definline judiciously, without any run-time
> overhead.
Absolutely. Clojure code is either short and slow or long and fast but not
short and fast like the F# example I already posted.
>> As an aside, the JVM even screwed up generics by using type erasure
>> instead of monomorphization and per-type instantiation at JIT => when the
>> JVM fails to optimize, generics are extremely slow.
>
> That's why if you need performance you use -server. Besides, Clojure
> doesn't care about Java's generics making them irrelevant.
Not if you want to compare with languages like F# that inherit
well-implemented generics from their VM.
>>> Just make a macro version of the function, or even a macro that can take
>>> a function's source code and spit out a macro version of that function.
>>
>> That only works if the entire source is written in Clojure.
>
> It works if that particular function's source is.
You cannot write "a macro that can take a function's source code and spit
out a macro version of that function" unless all of those functions are in
Clojure.
>>> I suggest you read up on functional programming as well.
>>
>> I am the author of the world's most profitable book on functional
>> programming.
>
> Let me guess: "Functional Programming for Dummies" or something on that
> level?
OCaml for Scientists and F# for Scientists:
http://www.ffconsultancy.com/products/ocaml_for_scientists/
http://www.ffconsultancy.com/products/fsharp_for_scientists/
> Many of the "problems" you cite go away with aggressive JIT
> optimization, which you get if you use the -server flag when you launch
> the JVM.
No, none of these problems "go away" with aggressive JIT optimization.
If you want to do direct interop with the graphics hardware on the JVM,
you use Java2D/Java3D.
>>>>>> This is fanboy fantasy, not reality.
>>>>> Yes.
>>>> Stop attacking me.
>>> I am not attacking you.
>> Sure you are. I wrote truth, and in response to that I got dumped on
>> with a steaming load of ad hominems.
>
> Ad hominem means personal attack.
Actually, "argumentum ad hominem" means "argument against the man",
which means instead of arguing against a point someone made you argued
that the identity or nature of the person making it somehow invalidates
it. The identity or nature of the person is, however, irrelevant, so
such arguments are fallacies.
Besides, calling me a "fanboy" whilst implying I'm delusional IS a
personal attack.
>>> Clojure offers trampolines to cover more general cases of indirect tail
>>> calls between different functions but it is much slower than real tail
>>> call elimination.
>> Balderdash.
>
> [argues some more]
Listen up, fuckface. I have personally written number-crunching Clojure
code and measured its performance. You are asking me to disbelieve the
evidence of my own eyes, just because your faith asserts that I can't
possibly have seen what I've seen.
I think we're done here. Not only are you clearly irrational, but you've
managed to frustrate me enough for me to use a cuss word. :P
>>>> I'm not sure what you mean by "value types".
>>> http://msdn.microsoft.com/en-us/library/s1ax56ch.aspx
>> I'm sorry, but I am asking you, not some web site (and especially not
>> some Microsoft web site), what you mean. If you don't want to actually
>> have a constructive dialog, feel free to STFU. Otherwise, actually say
>> something.
>
> Please familiarize yourself with the basic terminology
Please do not condescend to me. I've been working with, and programming,
computers for a quarter-century, and I've been doing number crunching
for almost as long. And I, unlike you, base my beliefs upon evidence
instead of faith.
>>>> If you mean non-pointer types, Clojure has access to the full range of
>>>> Java non-pointer types: boolean, byte, short, int, long, float, double,
>>>> and char.
>>> The ability to define custom value types is extremely valuable, most
>>> notably in the context of technical computing where you want 32- and
>>> 64-bit complex numbers, 2d vectors, 3d vectors in homogeneous
>>> coordinates, quaternions and dozens of other types to be representable
>>> without the overhead of boxing, heap allocating, stressing the garbage
>>> collector and so on.
>> First of all, I explained in previous posts that you can do that in
>> Java, and with full data abstraction in Clojure.
>
> No, this is impossible to do
But I've done it.
This is it. You basically just called me a liar there. I think I'm done
trying to reason with you. I judge that your reputation as a troll is
well-deserved. (Note that I had ignored that until now, choosing to base
my opinion upon evidence rather than hearsay. That is the difference
between us. But now that enough evidence is in, I find myself agreeing
with the hearsay. Funny, that.)
> array of structs that contain both ints and floats, for example. There is
> no way to represent that on the JVM because you only have an array of ints
> or an array of floats but not an array of structs composed of both ints and
> floats.
I don't suppose the concept of keeping separate-but-parallel arrays of
ints and floats (and wrapping this structure in a data abstraction
layer) occurred to you?
>> Second, if you define classes like Complex and Vect in Java with fields
>> of type double, the doubles don't get individually boxed.
>
> But the complex numbers and vectors do
So?
> which incurs massive performance degradation.
Codswallop.
I've debunked that argument enough times already; I won't bother to
repeat myself again here.
>> Third, the overhead of "heap allocating, stressing the garbage collector
>> and so on" in a modern JVM is about the same as the overhead of stack
>> allocating, on an amortized per-object basis: a pointer bump and
>> whatever construction is done to write values to memory.
>
> No
Yes.
Until you have learned something about the performance characteristics
of *modern* garbage collectors, you are not qualified to continue this
argument.
>>>> It can't currently pass them across function call boundaries without
>>>> boxing and unboxing, but a) if the function call is consistent, the JIT
>>>> can inline it and optimize away the boxing and unboxing, and b) Clojure
>>>> has macros, so it's possible to inline a function not being itself
>>>> passed across function calls without losing the function-call syntax.
>>> Only if your code is written entirely in Clojure which will not be the
>>> case
>> Why won't it?
>
> Because you will be calling library functions.
To do the numerics? Perhaps not. And if so, they shall be functions in a
high-performance numerics library. Either way, you lose.
>>> you are on the JVM to reuse existing Java libraries
>> Laughable. You may be on the JVM to get portability, or a top-notch GC,
>> or any combination of things. And if you are on the JVM to use existing
>> Java libraries, that usage might not be in the numeric parts of the
>> code...
>
> Or it might be JLAPACK
Or it might be Santa Claus. You can throw all kinds of "might be"s out
there, and as long as it also "might not be", you still lose.
> or it might be OpenGL which has had its performance degraded
That's news to me. I'm sure it'll be news to id Software too when they
hear it.
>> Last, but certainly not least, the Java libraries you're using might be
>> existing high-performance numerics libraries for Java! Or Java wrappers
>> around GMP or a similar native-code library.
>
> The JVM is also extremely slow to invoke external code (an order of
> magnitude slower than the CLR, for example) so those libraries also suffer
> from limitations of the JVM.
That would be a problem if you were stupid enough to call into JNI for
every single add, subtract, or multiply. Normally, you'd have larger,
longer-running tasks (perhaps entire number-crunching loops) called via
JNI, if you were using JNI. Not that you have to to get performance on a
*modern* JVM.
>>> but those libraries expose these deficiencies of the VM by providing
>>> non-generic interfaces.
>> A bit of Clojure magic could wrap these in much nicer interfaces even so
>> -- and, using macros or definline judiciously, without any run-time
>> overhead.
>
> Absolutely.
Ah, you're finally starting to see reason.
> Clojure code is either short and slow or long and fast
You have just capitulated by admitting that Clojure code can be fast.
> but not short and fast like the F# example I already posted.
Well, actually, if you tuck those support macros and functions away, the
same algorithm can be expressed just as concisely and run just as fast;
though it will call those macros and functions. Macros and functions
that can be reused in many such algorithms, or even made available as a
library. Using them is no more "cheating" or "bloating" than using GMP
from your C code would be.
>>> As an aside, the JVM even screwed up generics by using type erasure
>>> instead of monomorphization and per-type instantiation at JIT => when the
>>> JVM fails to optimize, generics are extremely slow.
>> That's why if you need performance you use -server. Besides, Clojure
>> doesn't care about Java's generics making them irrelevant.
>
> Not if you want to compare with languages like F# that inherit
> well-implemented generics from their VM.
Compare them regarding what? Not speed. It looks like you're on about
static typing now, which is a completely different flamewar. And one
this newsgroup has already had recently, if I'm not mistaken.
>>>> Just make a macro version of the function, or even a macro that can take
>>>> a function's source code and spit out a macro version of that function.
>>> That only works if the entire source is written in Clojure.
>> It works if that particular function's source is.
>
> You cannot write "a macro that can take a function's source code and spit
> out a macro version of that function" unless all of those functions are in
> Clojure.
Only the function to be macro-ized and the functions calling it have to
be written in Clojure. Furthermore, your objection is begging the
question. It assumes what you'd set out to prove, namely that "written
in Clojure = bad".
>>> I am the author of the world's most profitable book on functional
>>> programming.
>> Let me guess: "Functional Programming for Dummies" or something on that
>> level?
>
> OCaml
Irrelevant. We are discussing Clojure and other JVM languages.
> and F#
Microsoft associated and therefore evil.
>> Many of the "problems" you cite go away with aggressive JIT
>> optimization, which you get if you use the -server flag when you launch
>> the JVM.
>
> No
Yes.
You have lost.
Have a nice day.
They are means of implementing TCO.
>> I'm not sure what you mean by "value types".
>
> http://msdn.microsoft.com/en-us/library/s1ax56ch(VS.80).aspx
I'm sorry, but I prefer people to actually discuss something rather than
try to send me off to some web site. Especially some Microsoft web site.
>>> This goes way beyond number crunching though. Lots of applications
>>> benefit enormously from value types. They are used extensively in the
>>> .NET framework.
>> The JVM has several non-pointer types too...
>
> Value types are user-defined non-pointer types, i.e. structs.
There are several different uses of the phrase "value types". Why did it
take you this long to disambiguate?
> For example, you can define a complex type as a struct of two doubles
> or a Vertex type as a struct of three floats and three int16s.
Fascinating.
> In Clojure, you can workaround the lack of arrays of complex numbers using
> arrays of floats and syntactic abstraction to fudge the difference
> (Greenspunning instantiation-per-type generics which the JVM also lacks)
> but you cannot work around the general case.
Sure you can. For instance, for an array of your oddball Vertex type
above, use an array of 3N floats and a separate array of 3N int16s.
Allocate them one right after the other and you'll still have good
memory access locality, and you won't have much unboxing overhead (two
"boxes" means not much more unboxing than one and far less than N).
> This incurs huge performance degradation for programs on the JVM
Hogwash.
> and can make direct interop impossible (e.g. the JVM cannot express
> XNA).
Why do you think the JVM should have to "express XNA", whatever that
means? It can probably either use something else at least as good, or
else do it with one extra layer of indirection, a layer that becomes
very cheap after JIT optimization and hardware branch prediction and
caching.
Regardless, it becomes apparent (from all your mentions of F# and
microsoft.com URLs) that you are a Microsoft fanboi and therefore
religiously opposed to the JVM because, like Linux, it's one of the
things that Microsoft hates most: a competitor that just won't roll over
and die (DR-DOS), or be bought out (Yahoo), or be sued into submission
(TomTom); indeed, Sun had the gall to actually sue Microsoft and win once!
Well, either that or you're just a hypocrite and perhaps even a liar.
How else to explain your posts to the Clojure mailing list, some of them
directly contradicting things you've said here (including asserting, at
least twice, that Clojure numeric code can run at native-code speeds).
Jon Harrop wrote:
>> http://msdn.microsoft.com/en-us/library/s1ax56ch(VS.80).aspx
>
Oxide Scrubber wrote:
> I'm sorry,
Are you? Are you really?
> but I prefer people to actually discuss something rather than
> try to send me off to some web site. Especially some Microsoft web site.
>
Get off your high horse. Referencing a link is a perfectly legitimate
way to provide basic information such as that for which you ask. You
asked a question, he provided the information. That you for some
inexplicable reason want him to paraphrase a link that clearly and
succinctly answers your question is not his problem. How about you
accept his perfectly valid and comprehensive answer?
> There are several different uses of the phrase "value types". Why did it
> take you this long to disambiguate?
>
Others had no trouble whatsoever with the term. The moment you asked,
a couple of people responded with answers. Any faster and they'd've
answered before you asked.
> Regardless, it becomes apparent (from all your mentions of F# and
> microsoft.com URLs) that you are a Microsoft fanboi [sic] and therefore
> religiously opposed to the JVM because, like Linux, it's one of the
Straw-man and ad hominem arguments.
> things that Microsoft hates most: a competitor that just won't roll over
> and die (DR-DOS), or be bought out (Yahoo), or be sued into submission
> (TomTom); indeed, Sun had the gall to actually sue Microsoft and win once!
>
Your answer is somewhat off from the discussion, but taking point by
point:
Microsoft doesn't seem to show any emotion whatsoever, let alone hate,
with respect to the incidents you cited. DR-DOS killed itself; it
wasn't good enough to sustain itself in the market. Microsoft didn't
show any problem when Yahoo resisted the buyout; it simply started
another search-engine effort. Sun got very palsy-walsy with Microsoft
a couple of years ago, dropped the suit, and offered a joint
announcement with Microsoft that they were happy with each other.
Hardly evidence of hate.
Businesses compete. That's inherent to the capitalist system.
Businesses that compete effectively get to stay in business. That's
nothing for which to be angry with Microsoft. Indeed, you seem to be
showing a stronger interest in bashing Microsoft than addressing the
logic of Dr. Jon's posts.
I realize that it's fashionable to bash Microsoft, but it doesn't
prove anything.
> Well, either that or you're just a hypocrite and perhaps even a liar.
Ad hominem name-calling and completely inappropriate. Also, you
provide no evidence of hypocrisy or lies; such accusations put the
burden of proof on you, otherwise they're just pointless flaming.
> How else to explain your posts to the Clojure mailing list, some of them
> directly contradicting things you've said here (including asserting, at
> least twice, that Clojure numeric code can run at native-code speeds).
Perhaps he was discussing primitive numerics, for which the discussion
of value types would not apply. Such points would not apply to matrix
math, of course, and thus there would be no contradiction. Not being
a subscriber to those lists, I don't know. Perhaps you could quote
some of the allegedly contradictory posts verbatim for those of us who
follow in a different newsgroup?
Try to avoid flaming, and focus on presentation of evidence and logic.
--
Lew
Here is a toy C++ numerical example that uses templates, function
overloading, and operator overloading to provide a generic golden
section algorithm that will work for any UDT (and built-in types)
for which one provides the needed overloads and specializations.
template < class Vector >
Vector
golden_section (
Vector const & xa
, Vector const & xm
, Vector const & xb
) {
Vector const ma ( xa - xm ) ;
Vector const mb ( xb - xm ) ;
return mag(ma) > mag(mb) ?
xm + (ma * Constants< Scalar<Vector> >::goldenRatio()) :
xm + (mb * Constants< Scalar<Vector> >::goldenRatio()) ;
}
Can you please show how F#'s 'inline' provides the same benefits?
Ie how does F# with 'inline' support the above generic algorithm?
KHD
Can you explain why you posted to comp.lang.java.programmer ?
Arne
The thread has been cross-posted from the beginning. You will
need to ask either fft1976 or SG why it is so.
KHD
I assume that your newsreader have a little feature where you can
trim the groups being posted to.
A comparison between C++ and F# *may* be on topic in
comp.lang.functional, but it is utterly irrelevant in
comp.lang.java.programmer !
Arne
Oh, and your fingers just happened to type it because you don't have the
courtesy or self-control not to do it?
You are a troll and you are plonked.
> This is it. You basically just called me a liar there. I think I'm done
> trying to reason with you. I judge that your reputation as a troll is
He doesn't have that reputation, but you sure do.
Buh-bye, troll.
> well-deserved. (Note that I had ignored that until now, choosing to base
> my opinion upon evidence rather than hearsay. That is the difference
> between us. But now that enough evidence is in, I find myself agreeing
> with the hearsay. Funny, that.)
Troll.
> You have lost.
It ain't a contest, troll.
Plonk. You nasty piece of work.
--
Lew
Plonk.
Jon Harrop is well known in cll as a troll, and a quick google shows
that you have made your fair of trollish posts in cljp.
Harrop isn't a true troll. I run across his posts in a number of NGs I
subscribe to, and it might be more accurate to say that he'll make you
painstakingly prove your point. No question but that he's an OCaml/F#
zealot, but I've seen him operate in threads on comp.lang.haskell -
evidently trying to get things done in Haskell - without being an ass.
With respect to c.l.j.p, he clearly isn't overly fond of Java or the
JVM, but a lot of the people I see attempting to debate the guy on
Java/JVM topics seem to be pretty fluffy knowledge-wise (and what's
worse, they apparently don't know crap about other languages or the
CLR), so if they come off bruised that's no fault but their own.
AHS