And now's a perfect time to reflect on how the two languages evolved during the past decade. C++ obviously moved forward quite a bit -- cleaning up the loop constructs in particular. OCaml? Uh... there's F# for realists, Scheme for optimists, and Haskell for pedants. If you're actually writing OCaml web apps in OWebl I'd sure love to know why. Amazon released a native C++ SDK for AWS if you're into pain. If you're us…
Scheme and OCaml don't have that much in common really (unless you mean derivatives like typed racket, but even then). OWebl, in spite of its shiny website, is not what I would call "popular". You want to look at opium[1] or ocsigen/eliom [2]. Don't know what you have against OPAM, it's the best language-specific dependency manager I know. 1: https://github.com/rgrinberg/opium 2: http://ocsigen.org/eliom/
C++ vs. OCaml: Ray tracer comparison (2005)
21–30 of 47 posts
Re: C++ vs. OCaml: Ray tracer comparison (2005)
#22Kinda missing the point of C++ by using a linked-list. If you're going to spend the time to implement an algorithm in C++ at least take the time to make it cache aware. Otherwise it's not really surprising when the performance is the same when you're doing the exact same thing. Would be curious to see what the performance looks like with a tightly packed scene and static dispatch on a discrete number of primitives in…
It seems like the listed OCaml program has a default level of 9 where as the C++ one uses 6?
Times using original listing (minus print stmts):
$ time ./ray-cpp
real 0m3.369s
user 0m3.347s
sys 0m0.010s
$ time ./ray-ml
real 0m4.710s
user 0m4.703s
sys 0m0.003s
Time after changing the 9 in the ocaml program to a six: $ time ./ray-ml
real 0m4.032s
user 0m4.026s
sys 0m0.003s
Seems like C++ has a good edge. Above was ran on a 64 bit machine.Re: C++ vs. OCaml: Ray tracer comparison (2005)
#23Amazingly, there is no easy way to define a type in C++ which can be "one of these or one of these", e.g. a sphere or a group in this case. The author may have assumptions I'm missing here but the standard way to have a "one of these or one of these" thing is to have two classes inherent from a given abstract base class and use a pointer to the base class. If one wants the device specifically as a type, one could wra…
> The author may have assumptions I'm missing here but the standard way to have a "one of these or one of these" thing is to have two classes inherent from a given abstract base class and use a pointer to the base class. I think this is what the author describes in the sentence that follows the one you quoted. He also calls it "a common (ab)use of object oriented programming."
Re: C++ vs. OCaml: Ray tracer comparison (2005)
#24> With two cross-overs, there is little difference between the performance of the OCaml and C++ implementations. Note that the C++ was compiled with CPU-specific optimizations whereas the OCaml binary will run on any 486 compatible.
Ok, so the author is suggesting numerical C++ compiler generated SSE2+ code is comparable to OCaml 486, and thus with only very slow stack based x87 FPU available? SSE beats x87 hands down even without vectorization enabled, using a single float/double (scalar) per XMM vector register! That should make a significant difference in any ray-tracer worth 2 cents.
I didn't bother reading the source code, but I think it's very likely he didn't write C++ code like you should for a performance sensitive numerical application.
Although maybe the code for scene graph, bounding box and hit test was bad? FPU performance starts to matter once you actually find the ray intersecting object...
Anyways, usually if you do use C++, you do so because of specific performance requirements. Not to have the shortest or cleanest possible implementation.
Re: C++ vs. OCaml: Ray tracer comparison (2005)
#25These days with C++11's auto, this is improved a lot. It's not full type inference, but eliminates most of the boilerplate, and arguably what's left you really want to keep for documentation purposes.
> The object-oriented representation of a trivial sum type as an inheritance hierarchy of classes is needlessly inefficient.
This use case strikes me as a particularly bad example of sum types: The author wants to represent different kinds of scene members, like spheres and groups, as a sum type. Using a sum type means that anyone wanting to add a new kind of object has to add it to the sum type and handle it everywhere, which will quickly become problematic. Using object-oriented design allows new object types to be introduced without updating everything.
Basically the sum type looks nicer here only because it's a toy example and we're not considering how it will evolve.
That said, I do think sum types are really useful in some use cases, especially in compilers, and I'm sad C++ doesn't have them. I tend to end up defining ASTs using Cap'n Proto as a convenient way to declare a tagged union, even though I have no intent to serialize the structures.
> No need to write constructors for tuples, records and variant types in OCaml.
To be fair, for an all-public struct (as in the example), you don't need constructors in C++ either.
Once you have private members, then of course you need a constructor.
> Native lists in OCaml.
C++11 initializer lists make it basically possible to write list/vector/array classes that "feel native".
> Higher-order functions instead of loops in OCaml.
C++11 lambdas, etc. However, in a lot of cases, loops are easier to read.
Re: C++ vs. OCaml: Ray tracer comparison (2005)
#26Earlier quoted context omitted.
Scheme and OCaml don't have that much in common really (unless you mean derivatives like typed racket, but even then). OWebl, in spite of its shiny website, is not what I would call "popular". You want to look at opium[1] or ocsigen/eliom [2]. Don't know what you have against OPAM, it's the best language-specific dependency manager I know. 1: https://github.com/rgrinberg/opium 2: http://ocsigen.org/eliom/
My only problem with OPAM from the precisely eight seconds I've spent looking at it: 1) unsigned packages 2) not named something goofy like "OPamL." Serious missed opportunity there, guys.
Re: C++ vs. OCaml: Ray tracer comparison (2005)
#27Earlier quoted context omitted.
Let's see: opam as you mention. Loads of new libraries[0]. Lots of small evolutions in the language in OCaml 4 [1] [2]. Lots of work on optimization in ocamlopt. Aarch64, POWER7 & POWER8, replacement ARMv7 backends. OCaml is totally a practical language for writing real world applications. As I usually point out in these threads, Red Hat pay me to write OCaml programs[3], that are used by thousands of customers and m…
Looks like solid work all around. But if we could weigh it relative to the advancements in C++ the last decade, it wouldn't even show up on the scale. Red Hat could pay someone to do exactly what you're doing in many other languages with the exact same results. The only difference would be that the language in question would show up on the StackOverflow list of "most loved" or "most wanted" languages. Rust shows up i…
There are a few people at Red Hat and outside who contribute. To my knowledge none had prior experience with OCaml, but it's pretty easy to pick up.
Re: C++ vs. OCaml: Ray tracer comparison (2005)
#28Kinda missing the point of C++ by using a linked-list. If you're going to spend the time to implement an algorithm in C++ at least take the time to make it cache aware. Otherwise it's not really surprising when the performance is the same when you're doing the exact same thing. Would be curious to see what the performance looks like with a tightly packed scene and static dispatch on a discrete number of primitives in…
I was curious about whether using a vector over list would have any effect even though the size is so small and the answer seems no (I guess as it could be expected). It seems like the listed OCaml program has a default level of 9 where as the C++ one uses 6? Times using original listing (minus print stmts): $ time ./ray-cpp real 0m3.369s user 0m3.347s sys 0m0.010s $ time ./ray-ml real 0m4.710s user 0m4.703s sys 0m0.…
Lastly the virtual call again has the chance to cache miss(although probably only once seeing as we've just got a few impls).
In a small example like this there's a good chance that most of the heap allocations are close together but put this approach into production and you can very easily see fragmentation start driving up your cache misses.
(FWIW I'd also store radius*radius on creation, use a BSP/kd-tree and all sorts of other tricks that really help in these types of computations).
Re: C++ vs. OCaml: Ray tracer comparison (2005)
#29> Type inference removes the need to specify types explicitly over and over. These days with C++11's auto, this is improved a lot. It's not full type inference, but eliminates most of the boilerplate, and arguably what's left you really want to keep for documentation purposes. > The object-oriented representation of a trivial sum type as an inheritance hierarchy of classes is needlessly inefficient. This use case str…
Would be nice to see Rust's Option and Result ported over to C++ since I find that error handling extremely elegant compared to most C++ approaches.
Re: C++ vs. OCaml: Ray tracer comparison (2005)
#30Earlier quoted context omitted.
My only problem with OPAM from the precisely eight seconds I've spent looking at it: 1) unsigned packages 2) not named something goofy like "OPamL." Serious missed opportunity there, guys.
I think the daily quota of puns had been reached on that day. As for signing packages, I think it's being worked on, I remember reading something about it not that long ago.