From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.1.3 (2006-06-01) on yquem.inria.fr X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=AWL autolearn=disabled version=3.1.3 X-Original-To: caml-list@yquem.inria.fr Delivered-To: caml-list@yquem.inria.fr Received: from mail3-relais-sop.national.inria.fr (mail3-relais-sop.national.inria.fr [192.134.164.104]) by yquem.inria.fr (Postfix) with ESMTP id 04263BBC4 for ; Wed, 4 Mar 2009 22:24:07 +0100 (CET) X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AvABAD+ArknYi40JmWdsb2JhbACBTpM1AQEBAQEICwoHEcMrhAgG X-IronPort-AV: E=Sophos;i="4.38,302,1233529200"; d="scan'208";a="23872983" Received: from mail-out9.nyct.net (HELO mail.nyct.net) ([216.139.141.9]) by mail3-smtp-sop.national.inria.fr with ESMTP; 04 Mar 2009 22:24:06 +0100 Received: from beast.local (pool-96-250-33-211.nycmny.east.verizon.net [96.250.33.211]) (authenticated bits=0) by mail.nyct.net (8.14.2/8.14.1) with ESMTP id n24LNwk2000629 (version=TLSv1/SSLv3 cipher=DHE-DSS-AES256-SHA bits=256 verify=NO); Wed, 4 Mar 2009 16:24:04 -0500 (EST) (envelope-from bhurt@spnz.org) Date: Wed, 4 Mar 2009 16:23:53 -0500 (EST) From: Brian Hurt X-X-Sender: bhurt@beast To: Jon Harrop Cc: caml-list@yquem.inria.fr Subject: Re: [Caml-list] stl? In-Reply-To: <200903041945.23034.jon@ffconsultancy.com> Message-ID: References: <91a2ba3e0903031340wcdc976cp52522eb35f7ccb73@mail.gmail.com> <200903040159.48574.jon@ffconsultancy.com> <200903041945.23034.jon@ffconsultancy.com> User-Agent: Alpine 2.00 (DEB 1167 2008-08-23) MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII; format=flowed X-Spam: no; 0.00; stl:01 functors:01 abstracting:01 functors:01 ocaml:01 vectors:01 vectors:01 functor:01 functor:01 ocaml:01 lacks:01 compilation:01 abstraction:01 haskell:01 renders:01 On Wed, 4 Mar 2009, Jon Harrop wrote: > On Wednesday 04 March 2009 06:11:18 Brian Hurt wrote: >> On Wed, 4 Mar 2009, Jon Harrop wrote: >>> Efficiency is only important in the context of functors when abstracting >>> very fast and common functions like arithmetic without defunctorizing >>> your code. I don't think that is why people avoid functors in OCaml. >> >> Arithmetic operators that are themselves very cheap. The cost of >> functorization is large compared to, say, floating point addition- but >> small compared to the cost of, say, vector addition. > > Depends how big your vectors are. Less than it might seem. First of all, you have the allocation costs to hold the new vector- there's 3-5 clocks right there. Let's say the vectors are 3 elements long. So you have six loads and three stores- assume stores are free, and loads cost 1 clock apeice- they're in L1 cache, and they're getting preloaded. Plus the 3 clocks for the floating point adds. So that's 12-15 clock cycles right there. Say I'm being pessimistic by a factor of 2, and it's really only 6-8 clock cycles. Vr.s 10 clock cycles or so for the call via functor. Now we're down into the realm of only doubling the cost of the operation, not an order of magnitude increase. A single mispredicted branch or L1 cache miss that has to go out to L2 cache- not even main memory, just L2!- would blow the overhead of calling via functor out of the water. Premature optimization is the root of all evil. > >> And it's expensive only because Ocaml lacks an obvious optimization >> (defunctorization). > > If you neglect the enormous disadvantages: whole program analysis => no > incremental compilation and no DLLs. > > You can resolve the abstraction as soon as possible, as Haskell, does but then > you're on the slippery slope to wildly unpredictable performance that renders > the language too risky for a lot of real work. That explains why no one uses C++ for real work- since it resolves template abstractions as soon as possible, it' performance is so unpredictable that it renders the language too risky for a lot of real work. > >> And yet this whole discussion is simply proving my point- we're comparing >> clock cycles here. > > A circular argument: you brought up clock cycles. Yes. Because it's only at the point where you're counting clock cycles that the overhead of calling via a functor matters. > >> But for the vast bulk of people >> programming, performance (at least on the clock cycle level) simply isn't >> that important > > For some definition of "programming" that includes website design, maybe. Compare the number of people writing CRUD web applications in Ruby on Rails to the *entirity* of the professional Ocaml, SML, Haskell, and F# communities. I dare you. But no, not just web applications. Most business logic applications. Large chunks of the embedded world. Most desktop applications. Most code doesn't need to be "as fast as possible", it simply needs to be "fast enough". > >> - as demonstrated by all the "real work" being done in hideously slow >> languages like Ruby, Python, etc... > > Real work is done mostly in C++, Java and C# and proven predictable efficiency > is a huge part of that. You should have warned me before mentioning "Java" in the same sentence as "proven predictable efficiency". I was drinking when I read that, and now I have to clean my keyboard. It's a negligable part of that. Try this experiment. Go to J. Random software manager in Java/.Net/C++ shop. Ask them to list the reasons they use the language of choice. Don't prompt them, just let them list things in the order that comes to mind. Wait and see how long it is before "performance" comes up as an issue. Java currently has a decent- not great, but decent- performance story. Now. But Java became popular, and got into all of these coding shops, back when Java was either hideously slow, or radically unpredictable in performance. > F# can be much easier to work with than both OCaml and Haskell. Yep. And Ocaml can be much easier to work with than Haskell or F#. And Haskell can be much easier to work with then F# or Ocaml. > No, that is not overloading at all. You just replaced the functions wholesale. > > Operator overloading is about being able to reuse an identifier to refer to > different functions where the resolution depends upon the argument types. OK. So now we have a definition of what operator overloading is. Now, my question: what's it good for? It's obviously not necessary to write generic code- for example, a Newton's method that works on both floats and ratios. The only advantage I see is that you're able to use + instead of +. in many places. OK, this is an advantage- but hardly a major one. > You > have not accomplished that at all and your solution is uselessly fragile, > which is precisely it is practically unheard of in real OCaml code in this > context. > > Look at another example, Knuth's algorithm for numerically robust variance: > > let f (m, s, k) x = > let m' = m + (x - m) / float k > m', s + (x - m) * (x - m'), k + 1 > > The "+" operator is used to mean both floating point addition and integer > addition in the same expression. Functors cannot do that. You can replace "+" > with float and int versions but only when they are in separate modules, so > you not only end up breaking this simple expression into separate functions > but even into separate modules. That's obviously crazy useless and, indeed, > is precisely the motivation behind Christophe Troestlers's delimited > overloading syntax extension. So, let's rewrite the above code to use different operators for floating point and integer operations: let f (m, s, k) x = let m' = m +. (x -. m) /. float k m', s +. (x -. m) *. (x -. m'), k + 1 Oh yes, I see now. How much better it is if only we had operator overloading. > > So OCaml adopted + for int and +. for float. Sounds good but it scales really > badly when you introduce 2D and 3D homogeneous vectors and matrices, > arbitrary-dimensional vectors and matrices, quaternions, complex numbers and > even a 32-bit float type. You need something closer to genuine overloading. My experience in general has been that operators don't scale in complex cases. Number operators for number types scale better, but in any complicated case, and especially in most non-numeric cases, I prefer pseudo-english names. And I note that by far the most popular language for writing numeric code in, the all time champ for numerics, is Fortran. A language that didn't allow operator overloading or redefinition at all, and which forced you to use pseudo-english named functions if you wanted to add two matrixs together. For a definition of pseudo-english which is loose enough to include names like "dgemm". > > Right. > >>> However, that is trivial to fix with run-time type information that can >>> convey per-type functions. Both F# and my HLVM already do that. >> >> I suppose we could sit around and whine that Ocaml doesn't have type >> classes, or reflection, or some other neat feature, that if it only had >> it, we could all these neat things with them. >> >> Or we could use the equivalently powerfull features Ocaml *already* has... > > If you mean OCaml's objects, they also do not solve this problem. Wow. Just... wow. I spend page after page, message after message, singing the praises of functors, with out nearly a peep about the objects the whole time. And then, at the end of a message that was all about how great functors are, I mention "equivalently powerfull features", you immediately assume I'm refering to... objects. Truly, you have a dizzying intellect. Brian