<h2 style="font-weight: normal; font-family: arial,sans-serif;" class="title"><font size="2">Hello,</font></h2><br>I pasted a copy of the article below for those that cannot access the site.<br><br>I would be interested to see an article on Haskell in the same light as this Ocaml article, aka a constructive criticism of Haskell.&nbsp; <br>
<br>Enjoy!<br>__<br>Donnie<br><br><h2 style="font-weight: normal; font-family: arial,sans-serif;" class="title"><font size="2">### Begin Article ###<br></font></h2><h2 class="title"><a href="http://enfranchisedmind.com/blog/2008/05/07/why-ocaml-sucks/" rel="bookmark">Why Ocaml Sucks</a></h2>

            <div class="meta">
                                      <p>Published by <a href="http://enfranchisedmind.com/blog/author/bhurt-aw/" title="Posts by Brian">Brian</a> at 6:49 pm under <a href="http://enfranchisedmind.com/blog/categories/programming/functional-programming/" title="View all posts in Functional Languages: Ocaml, Haskell" rel="category tag">Functional Languages: Ocaml, Haskell</a> </p>

                              </div>
                              <div class="entry">
              <p>One
of the ways to not fall into the blub fallacy is to regularly consider
those ways in which your favorite language is inferior, and could be
improved- preferrably radically improved. Now, it should come as a
surprise to no one that my favorite language is (currently) Ocaml. So
as an intellectual exercise I want to list at least some of the ways
that Ocaml falls short as a language.</p>
<p>I will note that if you use this post as a reason to <em>not</em> use Ocaml, you are a fool and are missing the point of this post.  With the <em>possible</em> exception of Haskell, no other language I know of comes close to getting all the things right that Ocaml gets right.</p>

<p>So, with that in mind, let's begin.</p>
<p><span id="more-395"></span></p>
<ol><li>Lack of Parallelism
<p>In case you haven't guessed it from reading this blog, I
think parallelism is going to be the big problem for the next decade.
And while Ocaml does have threads, it also has a big ol' global
interpreter lock, so that only one thread can be executing Ocaml code
at a time. Which severely limits the utility of threads, and severely
limits the ability of Ocaml programmers to take advantage of multiple
cores. Now, to give the INRIA team credit, the reason they have for
this is a good one- we (programmers) still don't know for sure how to
write multithreaded code safely (I have my suspicions, but I have no
proof), and we had even less of an idea a decade and a half ago when
the fundamentals of Ocaml were being decided. And supporting
multithreaded code slows down the garbage collector. And, a decade and
a half ago, multithreaded code was a lot less important, and multicore
systems were rare and expensive. So this is mainly just Ocaml showing
it's age. But still, if I were to pick the biggest shortcomming of
Ocaml, this would be it.</p>
<p><br>
</p></li><li>Printf
<p>You know what? Printf was a bad idea for C- having this
special domain-specific language in what looks like strings to control
formatting. It's even worse in Ocaml, where you have to add special
kludges to the compiler to support it (at least the way Ocaml did it-
there are <a href="http://www.brics.dk/RS/98/12/" onclick="javascript:urchinTracker(&#39;/outbound/www.brics.dk/RS/98/12/?ref=http_//mail.google.com/a/darthik.com/?ui=2_view=bsp_ver=ymdfwq781tpu&#39;);">smarter ways</a> that don't require compiler kludges).  You might think that <code>"%3d"</code> is a string in Ocaml, and sometimes you'd be right.  But sometimes it's a <code>(int -&gt; '_a, '_b, '_c, '_a) format4</code>.  This horrid type (which is <em>not</em> a string) is necessary to encode the types of the arguments printf needs to be passed it.</p>

<p>The one thing I know of that C++ did better than Ocaml was
ditching printf. And the idea of iostreams even isn't that bad- except
for the fact that they encouraged generations of C++ programmers to
abuse operator overloading (hint to Bjarne Stroustrup: &lt;&lt; and
&gt;&gt; are not the I/O operators, they're the bit shift operators!),
and they made the iostream classes exceptionally difficult to inherit
from or extend. But a combination of C++ style iostream operators and
Java style iostream classes would have worked so much better, and not
required hacking the compiler. An even better idea might be some
variant of <a href="http://www.brics.dk/RS/98/12/" onclick="javascript:urchinTracker(&#39;/outbound/www.brics.dk/RS/98/12/?ref=http_//mail.google.com/a/darthik.com/?ui=2_view=bsp_ver=ymdfwq781tpu&#39;);">functional unparsing</a>.</p>
<br>
</li><li>Lack of multi-file modules
<p>Ocaml has an exceptionally powerfull and flexible module and
functor system, which stops rather annoyingly at the file level. Files
are modules, and files (and modules) can contain other modules within
them, but you can't collect several files into one big multi-file
module. You especially can't say that certain files, while they may be
visible to other modules within the multi-file module, aren't visible
outside the multi-file module. This is especially useful if you want to
factor out common base functionality from a library of modules into a
shared module, but not productize it for export to the outside world.
This limits the ability of the programmers to correctly structure large
projects.</p>
<p>The <code>-for-pack</code> arguments help fix a lot of this,
sorta- but they require smarts in the build system and generally
special .mli files to control visibility. It can be done, but it's not
clean- it makes the build process a lot more complex, and important
information about which files are externally visible or not is
contained somewhere that is not in the source code. This could
certainly be done a hell of a lot better than it is.</p>
<p><br>
</p></li><li>Mutable data
<p>Mutable data is both a blessing and a curse. It is a blessing
when learning the language, especially when you're coming from
conventional imperative programming languages. Rather than having to
learn what a lazy real time catenable dequeue is, and why you want one,
you can just bang out a quick mutable doubly linked list and get the
same behavior. I would argue that if you're coming from the
imperative/OO world, it's easier to learn Ocaml than Haskell for
precisely this reason. </p>
<p>But this implies that mutable data is training wheels of a
sort. And, like the fact that training wheels prevent you from going
fast, mutable data prevents Ocaml from doing a lot of interesting and
useful things. Many of Haskell's most interesting features- such as
STM, easy multithreading, and deforrestation, and scrap your
boilerplate, arise out of Haskell being purely applicative. Mutable
data is holding Ocaml back.</p>
<p><br>
</p></li><li>Strings
<p>This is more of a minor nit, but the representation of
strings as a (compact) array of chars is stupid. It made sense of
pointer-arithmetic C, not so much for Ocaml. The definition of chars as
8 bits prevents the internationalization of Ocaml beyond the European
languages, and the representation is inefficient. The most important
operations on strings are either iterating over all the characters in a
string, or concatenating two strings. Random access and mutation is
rare, <em>unless</em> you're using the string as a bit or byte array,
which is encouraged by the nature of strings. Bit arrays should be
first class types of themselves, with specialized internal
representations, allowing strings to be optimized as strings. An
unbalanced tree based structure would allow O(1) (and exceptionally
fast) string concatenation while preserving the O(N) cost to iterate
over all characters in a string. Also, strings are currently mutable
data, and as described above, mutable data is teh sucketh. This is
doubly so for strings, which can be profitably interned (and thus
should be).</p><br>
</li><li>Shift-reduce conflicts
<p>Shift-reduce conflicts happen in parser generators,
especially LALR(1) parser generators like yacc and ocamlyacc, where
there are situations where the parser doesn't know if the current
expression is complete, or can still go on. The golden example of this
is the "dangling else" problem of C and other languages, where you
might see code like this: </p><p><code></code></p><pre>    if (test1) then<br>        if (test2) then<br>            expr1<br>    else<br>        expr2</pre><p>The problem is that the parser, after it has finished parsing <code>expr1</code> expression and looking at the <code>else</code>, doesn't know wether to shift it (making the <code>else</code> and <code>expr2</code> part of the inner if) or reduce it (making the <code>else</code> part of the outer if).</p>

<p>I strongly recommend everyone who is developing a language to
write the initial syntax in a LALR(1) parser, and eliminate all
shift-reduce (and especially reduce-reduce) conflicts while you still
can, because every shift-reduce conflict is a bug waiting to happen. In
the above example, based on indenting, it is very likely to be meant to
be part of the outer if, but the parser is going to bind it to the
wrong if, causing a bug. This is slightly less bad in Ocaml, where
generally the bug will be a type error, but that doesn't mean it's
good. And Ocaml has literally dozens of these suckers lying in wait to
bite and unwary programmer. Even I get bitten by shift-reduce conflict
generated bugs on a regular basis.</p>
<p>A quick side digression for those who started yelling that
the indentation should be significant to the compiler. Consider the
output that would be caused by printing the following 3 C/Ocaml
strings: "\n \tx\n", "\n \t x\n", and "\n\t x\n". Each one starts with
a newline, ends with an x and a newline, and contains exactly two
spaces and a tab in between. Now, what columns do the three x's end up
in? The answer is "it depends upon which editor you're using to view
the output with, and what configuration that editor has". I just spent
a large chunk of this afternoon cleaning up a bunch of code written by
a programmer who merrily mixed spaces and tabs, and used a different
editor than I do. As a consequence, what looked neatly formatted to him
looked like gibberish to me. And if two humans can't agree on whether a
particular piece of code is well formatted or not, what hope does the
computer have to figure out the situation? The solution is to eliminate
the root cause of the problem (the shift-reduce conflicts), not add a
new way to introduce subtle and hard to debug errors.</p><br>
</li><li>Not_found
<p>One of the worst design decisions Ocaml has to have made is
Not_found- this is the exception that's thrown whenever something isn't
found. Tha'ts helpfull, isn't it? It's thrown by the Set and Map
modules (and all their functor applications) the List module, various
other data structure libraries, various regular expression libraries,
and, as a rule, just about any random peice of code. And it contains
absolutely no information as to what is not found, or what was being
looked for. Or even what was doing the looking. At least Failure and
Invalid_argument at least take a string argument, which is generally is
the name the function that failed. So if you see the exception
Invalid_argument("hd"), you know at least to be looking at calls to
List.hd (or to other functions named "hd"). But Not_found? This is the
sound of your hd hitting the desk, repeatedly.</p>

</li><li>Exceptions
<p>And while I'm ragging on Not_found, let me rag on exceptions
a bit. Exceptions are used way too commonly in Ocaml- OK, I'll give
Failure, Invalid_argument, and Assertion_failure a pass, but basically
Not_found and End_of_file should never, <em>ever</em>, be thrown.  Return 'a option instead.</p>
<p>This has non-trivial implications. For example, take the
classic newbie ocaml "mistake"- write a function that reads in a file
and returns the file as a list of strings, one string per line. Should
be easy. We use input_line as to read a line, and write our code like:</p>
<p><code></code></p><pre>let read_file desc =<br>    let rec loop accum =<br>        try<br>             let line = input desc in<br>             loop (line :: accum)<br>        with<br>         | End_of_file -&gt; List.rev accum<br>
    in loop []<br>;;</pre>
<p>And they can't understand why this code blows up when they
try to read a file with more than 30,000 lines in it. There are
standard solutions to this- but they make the code uglier, and by far
the best is to wrap the exception throwing code in an expression that
turns the exception into an option, like:</p>
<p><code></code></p><pre>let read_file desc =<br>    let rec loop accum =<br>         let line =<br>            try<br>                Some(input desc)<br>            with<br>            | End_of_file -&gt; None<br>        in<br>
        match line with<br>        | Some s -&gt; loop (s :: accum)<br>        | None -&gt; List.rev accum<br>    in loop []<br>;;</pre>
<p>At which point you really have to raise the question of why input_string didn't just return string_option from the get-go.</p>
<p>The other popular alternative is to use mutable data.  Which is just trading off one problem set for another.</p>
<p>There is, by the way, an interesting idea for expetion handling that's been raised recently (see <a href="http://dx.doi.org/10.1017/S0956796801004099" onclick="javascript:urchinTracker(&#39;/outbound/dx.doi.org/10.1017/S0956796801004099?ref=http_//mail.google.com/a/darthik.com/?ui=2_view=bsp_ver=ymdfwq781tpu&#39;);">here</a> and <a href="http://portal.acm.org/citation.cfm?id=1022471.1022475" onclick="javascript:urchinTracker(&#39;/outbound/portal.acm.org/citation.cfm?id=1022471.1022475?ref=http_//mail.google.com/a/darthik.com/?ui=2_view=bsp_ver=ymdfwq781tpu&#39;);">here</a>).  The basic idea is that the current Ocaml syntax for declaring an exception handler is:</p>

<p><code></code></p><pre>    try<br>        expr1<br>    with<br>    | Exception -&gt; expr2</pre>
<p>where if <code>expr1</code> doesn't throw an exception, the value of the hole expression is the value returned by <code>expr1</code>- otherwise, if it throws <code>Exception</code>, then the whole expression has the value <code>expr2</code>.  This syntax is replaced by:</p>

<p><code></code></p><pre>    try var = expr1 in<br>    expr2<br>    with<br>    | Exception -&gt; expr3</pre>
<p>Here, if <code>expr1</code> does not throw an exception, then the value of the whole expression is that of <code>expr2</code> with variable <code>var</code> having the value of <code>expr1</code>, while if it throws <code>Exception</code>, then the value of the whole expression is then <code>expr3</code>.  Note that exceptions are only caught in <code>expr1</code>- it's just that if an exception is caught, then <code>expr2</code> is skipped as well.  But this means that calls from within <code>expr2</code> can be tail calls.  Let's take a look at our <code>read_file</code> program, the newbie way, a third time, this time with our new exception syntax:</p>

<p><code></code></p><pre>let read_file desc =<br>    let rec loop accum = <br>        try line = input_line desc in <br>        loop (line :: accum)<br>        with | End_of_file -&gt; List.rev accum<br>    in<br>    loop []<br>
;;</pre>
<p>Since the tail call to <code>loop</code> is outside where we
catch exceptions, it's a true tail call, and the function works "as
expected". And the fact that we're using exceptions instead of options
isn't that big of a deal anymore (Not_found still sucks, due to it's
simple ubiquity and taciturnity). If someone with more time and/or
camlp4 knowledge than I have wants to write this up as an extension,
I'd be eternally gratefull.</p>
<p>While I'm at it, would it be possible to have exceptions in
the type system? I know Java tried this and everyone hated it, but
Ocaml has two things that Java didn't- type inference and type
variables. The type variables are nice because they allow you to deal
with "unknown" exceptions- for example you could have a function of
type <code>(int -&gt; int throws 'a) -&gt; int throws 'a</code>,
meaning that you don't know (or care) what exceptions the passed-in
funciton might throw, but that you throw the same exceptions
(presumably by calling the passed-in function). Type inference also
means you don't have to declare most of these cases, the compiler can
infer what exceptions are thrown. This level of changes to the type
system are highly unlikely, but a boy can dream, can't he?</p>

</li><li>Deforrestation
<p>This really should be under the "mutable data is the sucketh"
section, but oh well. Haskell has introduced a very interesting and (to
my knowledge) unique layer of optimization, called deforrestation.
Basically, what happens if that the ghc compiler recognizes and can
optimize certain common sub-optimal data structure transformations. For
example, it can convert <code>map f (map g lst)</code> into <code>map (f . g) lst</code>, where the peroid (<code>.</code>)
is the function composition operator. There are a couple of obvious
advantages to being able to do this- for example, by doing so we've
eliminated an intermediate data structure, and created new
opportunities for optimizing the combined f and g functions.</p>
<p>But there are two things of serious interest to me about
this. First of all, this is the first time I've seen optimizations at
this level being this easily performed. Companies like Intel and IBM
have thrown literally man-millenia at this problem, and the solutions
they've come up with were limited and fragile (slight changes to the
code would enable or disable the optimization). And yet the Haskell
people implemented in one Simon Peyton Jones long weekend (also known
as a couple of man months for mere mortals like you and I). The reason
for this is that the real difficult is not actually implementing the
transformation, or even detecting that the transformation might be
applicable, it's proving that the transformation is correct, that the
code after the transformation is applied behaves identically to the
code before the transformation is applied. In langauges with mutable
data, like Fortran and C++ (and Ocaml), this is decidedly non-trivial.
In Haskell, you can dash off the proof that it's always correct on the
back of a cocktail napkin- proving that it's correct in the general
case for all lists and all functions. And that thus the compiler
doesn't even need to check- once it detects that the pattern can be
applied, it can just go ahead and apply it. Haskell is doing data
structure level optimizations with the ease that most other compiler do
peephole instruction optimization. This is a non-trivial result.</p>
<p>The second important aspect of this is that it changes the
concept of what optimization is, or should be. I forget which paper it
was I was reading that said that optimization should really be called
depessimization. That the programmer wants to introduce pessimizations-
the programmer could do the above deforrestation himself, except that
to do so would make maintainance more difficult, as it'd break module
boundaries, or requires knowledge of how a particular module is
implemented, or simply requires knowledge of widely seperated peices of
code. The goal of the compiler, rather than striving to produce some
"optimal" (and thus impossible to obtain) implementation, but simple to
undo the pessimizations that the programmer has introduced in the name
of maintainablity, modularity, readability, and/or simplicity. The
programmer shouldn't have to worry about creating intermediate data
structures, and should worry about corrupting his code in the name of
performance- that's the compilers job (don't break your code, let the
computer do that for you! :-).</p>
<p>Needless to say, between the mutable data, the side effects,
and the handling of exceptions, Ocaml isn't going get deforrestation
any time soon.</p><br>
</li><li>Limited standard library
<p>If writing monad tutorials is the cottage industry of Haskell
programmers, than rewriting the standard library is Ocaml's cottage
industry. You almost can't call yourself an Ocaml programmer if you
haven't rewritten a goodly chunk of the standard library at least once.
This is because every Ocaml programmer has a long list of functions
that should (they think) be in the standard library but just aren't.
The big ones for me are the lack of Int and Float modules ready for use
by the Set and Map functors, the lack of an already-instantiated Map
and Set modules for Strings, Ints, and Floats, and the lack of a list
to set/map function. None of these are exactly hard to do, just
annoying to have to constantly redo.</p>
<p>Of course, the problem with this is the range and design
patterns of Ocaml programmers- especially with comparison to languages
like Java and C++, or even Ruby. The design patterns of a top-5% Java
programmer is not all that different from the design philosophy of a
bottom-30%'er. There may be differences in precisely what features are
supported, and what names things are given may change, but the broad
stroke designs will be similiar. The design patterns of Brian Hurt
circa 2008 are radically different than the design patterns of Brian
Hurt circa 2003. For example, were I to redo extlib now, it's be purely
applicative, heavily functorized, lots of monads, and a fair bit of
lazy evaluation, as opposed to the code I wrote in 2003.</p>
<p><br>
</p></li><li>Slow lazy
<p>Speaking of lazy evaluation- Ocaml's built-in lazy evaluation
is wicked slow. I've actually timed it, and it's like 130+ clock cycles
of overhead to force a lazy value the first time, and over 70 clock
cycles of overhead to force it the second and subsequent times (when
all it has to do is return the cached value). Given that most of the
good uses of lazy evaluation has it wrapping computations that are like
10 clock cycles long or so, the overhead of the lazy thunk dominates.
In this era of Ruby programmers, this may not seem like much- but this
overhead discourages Ocaml programmers from using lazy evaluation.
Which is a shame, as anyone who has read Okasaki knows how frimping
usefull it is.</p><br>
</li><br></ol>
<p>Well, that's my list so far- subject to revision without
notice. The vast majority of them qualify as picking nits- and they
are. If you can damn with faint praise, then you should also be able to
praise with faint damning- and this certainly qualifies as that. Most
of the problems here only became apparent (or their solutions became
apparent) long after Ocaml was mature and set. For example, it's only
be recently that multi-threading has been a big deal. And the
usefullness of monads and lazy evaluation for functional programming
weren't understood until the late nineties/early 21st, a decade after
Ocaml's formative years. So this whole post mostly amounts to whining
that the Ocaml developers weren't <em>even more insightfull and foresightfull</em>
than they were. And, compared to the major revisions Ocaml's
"age-mates" Java and Perl have gone through, it's stood up well with
the passing of time.</p>
<p>No lanuage is perfect, including Ocaml. And to continue to
improve we must understand what has gone before- both what worked, and
what didn't.</p>
<p class="akpc_pop">Popularity: 6% <span class="akpc_help">[<a href="http://alexking.org/projects/wordpress/popularity-contest" title="What does this mean?" onclick="javascript:urchinTracker(&#39;/outbound/alexking.org/projects/wordpress/popularity-contest?ref=http_//mail.google.com/a/darthik.com/?ui=2_view=bsp_ver=ymdfwq781tpu&#39;);">?</a>]</span></p>
                                            </div>### End Article ###<br><br><br><div class="gmail_quote">On Thu, May 8, 2008 at 2:27 PM, Andrew Coppin &lt;<a href="mailto:andrewcoppin@btinternet.com">andrewcoppin@btinternet.com</a>&gt; wrote:<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><div class="Ih2E3d">Chad Scherrer wrote:<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
PS - the link now gives a &quot;500 server error&quot; - did our traffic overwhelm it? Is<br>
the cafe the next slashdot? ;)<br>
 &nbsp;<br>
</blockquote>
<br></div>
Hell, I can&#39;t even get a TCP SYN-ACK packet out of it... :-/<div><div></div><div class="Wj3C7c"><br>
<br>
_______________________________________________<br>
Haskell-Cafe mailing list<br>
<a href="mailto:Haskell-Cafe@haskell.org" target="_blank">Haskell-Cafe@haskell.org</a><br>
<a href="http://www.haskell.org/mailman/listinfo/haskell-cafe" target="_blank">http://www.haskell.org/mailman/listinfo/haskell-cafe</a><br>
</div></div></blockquote></div><br>