Comments

(newest first)

  • Bilyan Borisov | Fri, 24 Jan 2014 15:01:30 UTC

    Great article! In my opinion, most of the critics of OCaml in the comments have overlooked the fact that the language can be compiled down not only to byte code but also to native code. In the long run, a compiled application will always be faster than a Python-Ruby-Perl script. 
    
    Conciseness aside (even though I totally agree that functional languages, with OCaml as an example, are much more succinct than Java/C++), static typing and type inference are enormously good even for moderate and small sized projects. Again, this is all a personal preference, but logically speaking a dynamically typed language will 'let you do nasty things' like :
    
    >> 4 == None
    
    which evaluate to False in Python, which will give rise to a TON of bugs that only semantic testing can catch since this is syntactically OK. 
    
    Therefore, even if we assume that Python is as succinct as OCaml (or any other statically typed and compiled functional language) it will always be slower and will leave a larger margin for introducing bugs in huge codebases. However, again as the author suggests, Python does have a very serious advantage, namely, its extensive set of libraries but I personally think that they give the inexperienced programmer a false sense of awesomeness  since you get the illusion of being able to do a lot without much effort.
    
    At the end of the day languages are still tools and we still love them and defend them dearly so I guess everything goes in the 'which programming language is the best' discussion.
  • Kevin Kinnell | Thu, 11 Oct 2012 19:59:40 UTC

    "First class" is a CS definition, and according to that definition CL has first class functions.  I got it wrong, because I didn't really say what I meant.
    
    I should have said "easily usable first class functions."
    
    Sorry about that.
  • Jesse Talbutt | Sun, 19 Aug 2012 16:10:16 UTC

    Unless the robot in question is the one in the first scene of Robocop.  Then I'd probably use a more strongly typed language.
  • Jesse Talbutt | Sun, 19 Aug 2012 15:59:42 UTC

    Common LISP does, in fact, have first-class functions.  It's one of the sine qua nons of the language - i'm not sure how anyone could get that wrong.
    
    The main difference between LISP and Scheme is that LISP uses separate namespaces for its functions and its variables, which is an abstract that's both incredibly powerful and incredibly dangerous:  all it takes is one "clever" code-writer using that feature to crack open a closure and you get unpredictable side-effects.  I read this article wondering "if they're going to use OCaml, why not just go whole hog and use LISP" but I see the issue now - OCaml is like a LISP where you sacrifice power that you'll probably never use in exchange for safety: likely a premium when you're dealing with large financial transactions in real-time instead of, say, creating a natural language DSL for robots.
  • Kevin Kinnell | Mon, 11 Jun 2012 23:17:33 UTC

    Drat.  I meant "last few paragraphs."  C'est l'ecriture.
  • Kevin Kinnell | Mon, 11 Jun 2012 23:03:35 UTC

    The readability of any code is related to knowledge of 1) the purpose of the code, 2) the language the code is written in, and 3) -- and please pardon the pun -- the knowledge of the coder.
    
    One can argue that literate programming obviates (1) but what it actually seems to do in practice is to add a highly-technical natural-language narrative that wrecks the flow of the program.  It becomes something like reading a legal brief.  Fine -- if you're a lawyer, with extensive knowledge of the arcane (meta) language of law.  My apologies, Dr. Knuth, but there it is.  The actual cure for (1) is a combination of a good description of the purpose of the code, and good comments.
    
    (3) is more or less a combination of innate ability and experience, whether we're talking about the writer or the reader of the code.  I'd bet NO CODE reads like a natural language, but certainly there isn't any that reads like English.  If you think it does, it's because you have ability and experience.  Arguably, the process of "speaking" in a programming language seems to mirror the process of learning a natural language.  In particular, the whole gamut of "native speakers" is there -- you can have babies talking to babies, babies talking to adults, well educated adults talking to less educated adults, etc.  It's quite a bit of fun to observe.  The knowledge of the coders, both the reader and the writer, is a big part of readability.  Anybody who can make a language that somehow skirts this is, in my opinion, some sort of supernatural being.
    
    That leaves (2), the language the code is written in.  The closest-to-objective view of that is, I think, how quickly a reader can grasp the overall purpose of a coding sequence, and integrate that into the flow of a program.  In other words, can the code be "grokked" easily?
    
    You can create a language which makes this almost impossible to achieve -- APL comes to mind.  No one could argue that APL isn't concise.  Gaining the experience necessary to be able to read APL like a natural language is probably denied most ordinary mortals by their finite lifespan.   I doubt that anyone can grok APL, even if they wrote the code.
    
    At the other extreme there're COBOL and Java (one programmer's opinion, of course.)  If you can actually grok code written in either of these you can make a pile of money, but you have sold your soul.
    
    Lisps tend to be interrupted by their closing parentheses, but you can learn not to see them.  Lisps also use a REPL, giving them the benefit of incremental coding.  Unfortunately, except for Scheme dialects, functions aren't first-class in Lisps.  Lisp can be grokked, but it's missing some expressive power, especially built-programmable types and type checking,  making computation with types a huge burden on the programmer.
    
    Perl goes beyond Lisp in concision, and its scope-control is as good as it gets.  But Perl has a steep learning curve for fluency, and functions aren't really first-class, Perl lacks a usable REPL, and Perl is missing automated type checking.
    
    OCaml manages to be concise, allows computation with types, makes functions first-class objects, has a visually clean syntax, has a REPL, does not require "purity" (thus allowing coder-readable access to the real world) and seems to be quite easy to learn--can you imagine a trading company requiring its traders to learn any of the languages in the last paragraph?
    
    Well expressed OCaml code is easy to grok.
    
    I think Dr. Minsky makes his case.
  • Fredrik Skeel L√łkke | Tue, 13 Mar 2012 18:25:46 UTC

    It would be wonderfull to hear how the language plays out in the context of tests. Especially regarding tests involving stubbing of external resources.
  • Rowan | Fri, 09 Mar 2012 05:41:37 UTC

    @name on "more practical":  Actually, monadic effects and the like are quite common in OCaml.   In fact about 1 month before you posted your comment, Yaron (the author) also announced a new monadic concurrency library called Async:  https://ocaml.janestreet.com/?q=node/100  
    
    For unintended side-effects, it's more a library issue than a language issue: it's pretty easy in OCaml to encapsulate effects in a monadic library, and then only use the monadic versions, banning other uses or considering them unsafe in a similar sense to Haskell's "unsafePerformIO".
    
    To me the main reason I tend not to use Haskell except for small projects is that I've hit the unintended side-effect of "allocating massive amounts of memory and thrashing or crashing" and sometimes been unable to resolve it without digging deep into the source code of multiple libraries written by different authors.  This is improving in Haskell, but I'd still trust OCaml much more for critical systems like the one described.
  • gkannan | Thu, 12 Jan 2012 15:57:31 UTC

    Excellent article. 
  • name | Thu, 22 Dec 2011 22:27:19 UTC

    "more practical". Wow, those are weasel words if ever I heard them.
    
    Haskell is way "more practical" (you see what I did there?) for me than O'Caml. O'Caml is great, but it doesn't even try to prevent unintended side-effects. (The whole Applicative/Semiring/Monoid/Monad/MonadT is insanely useful and rewarding if you just try it "fo' realz".)
  • izan | Sat, 03 Dec 2011 21:19:05 UTC

    It seems to me that Ocaml provides, in programming languages,  the best tradeoff for performance, memory footprint and expressiveness.
  • zaxis | Tue, 15 Nov 2011 12:17:07 UTC

    OCaml is a great langauge which is more practical than haskell.  However, i canot find a killer application like Rails in OCaml.
  • Polo | Wed, 02 Nov 2011 19:26:32 UTC

    It's a very excellent article!  
    I'll try out OCaml ASAP and let you know about the experience.
    Regards!
  • Matt | Sat, 15 Oct 2011 03:34:55 UTC

    I have to drop in just to say that no, Go is not the answer. It tacks on a few modern features but it's 20 years behind the times.
  • Bernd | Thu, 13 Oct 2011 22:59:03 UTC

    I love the algebraic datatype, that it can be defined quite short. But note, that Enumerations in Java just work the same:
    
    public Enum State {
      Connecting() { Timestamp when; },
      Connected() { Timestamp last; String sessionID; }
      Disconnected() { Timestamp when; }
    }
    
    Greetings
    Bernd
  • Pedro | Fri, 07 Oct 2011 14:21:54 UTC

    Re the comment by Ahmed: the issues with parallelism in OCaml are a specific to the implementation but not Haskell. The GHC compiler has a very good support for parallelism (par annotations, strategies, data parallelism) and explicit concurrency (lightweight threads, STM).
    Check the Haskell web page for details: http://haskell.org/haskellwiki/Parallel
  • Paul Steckler | Thu, 06 Oct 2011 11:36:58 UTC

    I've been using OCaml on a project for the last 3 years with fair success.
    
    Two features are available via libraries that I would find even more useful were the technology integrated into the language. One feature is the Unicode support offered by the camomile library. In 2011, there's no excuse not to support Unicode strings natively. The other feature is the Haskell-inspired feature offered by the "deriving" library. The ability to pretty-print a value of arbitrary type is tremendously useful.
    
    Also, the camlp4 preprocessor is useful, but too fiddly to use, in my opinion. Maybe it gets easier with practice.
    I've written some camlp4 macros for our code -- it took much longer than I would've liked to get those right.
    
  • Ahmed | Thu, 06 Oct 2011 05:23:03 UTC

    The lack of parallelism in OCaml, Haskell and co is why I have chosen Erlang as the functional lang of choice. It is about time that parallel processing gets the attention it so deserves!
  • Raffalli | Wed, 05 Oct 2011 00:55:18 UTC

    People should recall taht OCaml is an object oriented (hence the O), functional and procedural language ...
    
  • John Fro | Tue, 04 Oct 2011 21:44:23 UTC

    The point of OO languages is to segregate work effort in a team effort.  The smaller the team, the less likely it is of benefit.  Publishing a class API is the actual key to readability.  If you don't understand the API then you should probably use another class or rewrite it.  The worst issue is when there is no API documentation and the project is large.  Then you are looking at a rewrite.  Most people prefer the languages they are most familiar with and a wide working experience of languages is rare.
  • Abram Hindle | Tue, 04 Oct 2011 19:17:11 UTC

    We have previous work that could used to empirically reason about OCaml's readability.
    
    One could try to make this argument empirically. Buse and Weimer measured code readability by asking 100 participants to rank 100 code snippets by readability, they released their data! Daryl Posnett and I  poured over the data and looked at English readability metrics. We determined that English readability was based on loose ideas of Entropy, and that Halstead's V was like a naive entropy that was programming language aware. We found that by combining Halstead's V, token entropy and character entropy we had a model of source readability that performed very well with respect to the mean opinion scores extracted by Buse et al. (R. Buse and W. Weimer. Learning a Metric for Code Readability. Software Engineering, IEEE Transactions on, 36(4):546558, 2010). 
    
    What does this mean for OCaml?
    
    First, of the use of type inference means less tokens per 8 line snippet, this means that entropy and Halstead V will be lower meaning the code is likely to more readability than code full of type annotations.
    
    Second, the use of higher order functions allows for code reuse without the pain of expanding on the types, this probably would improve code readability.
    
    Third, the programming language shootout consistently demonstrates that OCaml code is pretty small in terms of LOC. Since tokens and LOC are correlated we assume this means less tokens too (you could measure this).
    
    Using all of these arguments with our model you could argue that OCaml was more readable based on a model trained with actual evidence. Threats include that it is a different language (Java is not OCaml) and snippet sizes are of course different.
    
    In character entropy alone, the Java snippet is 4.4 bits per character and the OCaml was 3.9 bits per character. 
    
    Summary: Our simple model of readability, based on information theory, can be used to argue that OCaml code is more readable than languages like Java.
    
    The work was published at MSR2011 and is available here: http://softwareprocess.es/index.cgi/Readability
    
  • Tao Liu | Tue, 04 Oct 2011 17:17:47 UTC

    Yes, I like F# much better. :-)
  • Donna Malayeri | Tue, 04 Oct 2011 17:03:35 UTC

    (Forgot to add the disclaimer!  I'm the program manager of F# at Microsoft.)
  • Donna Malayeri | Tue, 04 Oct 2011 17:00:33 UTC

    Excellent article!  I especially appreciated the Python example.
    
    One thing to note, however, is that tooling for functional languages has a number of challenges that are not present in imperative languages. For instance, you might want to set a breakpoint within a lambda (or any sub-expression), and I don't know of any debuggers that yet support this.
    
    Visual Studio does have some nice tooling for F#, which I have found to be a productivity boost. With regard to parallelism, F# supports asynchronous workflows (http://research.microsoft.com/apps/pubs/default.aspx?id=147194), which are quite elegant.
  • AlefSin | Tue, 04 Oct 2011 10:16:04 UTC

    You mentioned two major limitations for OCaml: 1) platform libraries and tools and 2) parallelism. Considering that in your examples you have compared C# and OCaml several times, what do you think about F#? I think F# at least takes care of the first problem nicely. Also since it can talk to C# easily, some nasty bits of code (like the GUI related part) can be handed over to C# while the core of the application can be entirely in F#. 
  • Anne Ominous | Mon, 03 Oct 2011 20:38:59 UTC

    What nonsense.
    
    Java is notoriously verbose; using it to illustrate concision in other languages is like using an Escalade to compare gas mileage against a Prius.
    
    Further, I argue that the whole argument here is based on an invalid premise: that more concise is necessarily better and easier to read than verboseness. That is not necessarily the case, even within the same language.
    
    In Ruby, for example, one can write a one-line lambda which, outside of a lambda, might take 5 or 6 lines or so of code to write. However, the lambda is not necessarily easier to read; on the contrary, they tend to obfuscate what is really happening, compared to the spelled-out version.
    
  • paull | Sat, 01 Oct 2011 17:25:50 UTC

    Just like ocaml and Scala, the Vienna Development Method language is a great language to prototype
    and test throw-away OO and non-OO code. Think of it of the UML Object Constraint Language on steroids.
    There a development tool for it called Overture.
    
    Here's the destutter function in VDM:
    
    module Test
    	exports all
    	definitions
    
    	types
    
    	values
    
    	functions
    
    		destutter : seq of nat -> seq of nat
    		destutter(l) ==
    			cases l :
    				[] -> [],
    				[x] ^ [] -> [x] ^ [],
    				[x,y] ^ l2 -> 
    					if x = y then
    						destutter([y] ^ l2)
    					else
    						[x] ^ destutter([y] ^ l2)
    			end;
    
    		
    		test: () -> seq of nat
    		test() == 
    			let s1 = [1,1,1,2,2,2,3,3,3,3,3,4,55555,6,7]
    				in destutter(s1);
    
    	traces
    
    		T1: let s1 = [0,1,2,3,4] in destutter(s1);
    
    		T2: let s1 = [0,1,1,2,3,3,3,4,4,4,4,4] in destutter(s1);
    
    end Test
  • greymont | Fri, 30 Sep 2011 20:37:19 UTC

    Interesting situation. I could almost replace OCaml with Object Pascal (Delphi) and it would read well in a similar way. Minority language, overlooked by many who should know better, statically typed, if you get it to compile you are more than half way to a solution, etc.
  • Tim Daly | Thu, 29 Sep 2011 14:18:55 UTC

    You stress the need for "software that was readable". I suggest that the reason the software is
    considered "readable" is that you are one of the authors. Code only says "how", it does not say
    "why".
    
    I am the lead developer on an open source project (Axiom). I was one of the original developers.
    In general, I write dirt-simple, easy-to-read code. Axiom was sold commercially and I left the project.
    Years laters Axiom was withdrawn from the market and given to me to open source. Amazingly I
    found that I could read my own code but I had no idea WHY I had written the functions. It turns out
    that the missing "why" is crucial to keeping the system "alive". Your company will only understand
    this when the key developers move on and the maintenance programmers arrive. By then it will be
    too late.
    
    The lesson I learned is that developers need to capture the "why". The best tool for that job seems to
    be literate programming. The basic idea of a literate program is that code should be read like a novel.
    Each character (e.g. a function) should have a reason to be introduced, that is, it should be motivated.
    A new programmer on your team should be able to pick up the "book", read it for a few weeks, and be
    up to speed on the whole system. New code should go through an Editor-in-Chief, hopefully an English
    major who doesn't program, to edit it as any usual publication.
    
    See Lisp in Small Pieces by Christian Quiennac for an example of a great literate program.
    It includes the working source code for a complete lisp system surrounded by excellent prose that
    explains all of the concepts.
    
    The long term benefit is something you will never see as you already understand the code. But the
    company DEPENDS on this code and when you leave they will lose a great deal of information
    necessary to maintain the code and the code quality.
  • bltxd | Thu, 29 Sep 2011 10:08:33 UTC

    @JDI:
    The nice thing about pattern matching is that it reads like truth tables. It's hard to make things simpler.
    
    And pattern matching in OCaml (and probably other ML languages) has other benefits : the compiler will warn you if your matches are not exhaustive (as demonstrated), but it will also warn you when one of your matches is shadowed by others (extremely useful when the patterns matched are not trivial).
    
    PS: Go ? Are you kidding ?
    
  • artyom | Thu, 29 Sep 2011 05:29:34 UTC

    @JDI: the example is meant to demonstrate the utility of algebraic datatypes (aka tagged unions) and the compiler-enforced pattern matching exhaustiveness, and not syntactic sugar facilities for making code resemble a natural language. You've missed the point.
  • Adam Koprowski | Wed, 28 Sep 2011 22:40:08 UTC

    Great article and I couldn't agree more with the conclusions: Ocaml is a truly great programming language and its type-system is indeed amazingly effective at catching all sorts of programming errors.
    If anyone liking Ocaml is interested in web development I'd like to recommend Opa (http://opalang.org). Implemented in Ocaml and bearing lots of similarities to it (strong static type-checking with inference, very concise, mostly pure) but very modern (fresh out of the factory ;) and targeted at web development.
    [Disclaimer: I'm part of the team working on Opa]
  • g_ | Wed, 28 Sep 2011 21:39:19 UTC

    You're overstating the simplicity of your python example, it doesn't read any more like plain english than the OCaml code. If it does to you, then it's only because of your familiarity with python syntax and functions, or lack of similar understanding of the OCaml dito. Those things aside, that example in the article isn't about code beauty, but the power of the OCaml type system.
  • JDI | Wed, 28 Sep 2011 19:07:42 UTC

    ... Of course the comment post then strips my newlines and botches my example formatting, lol.
  • JDI | Wed, 28 Sep 2011 18:43:48 UTC

    I was somewhat disappointed at the python destutter example. I think if you are going to provide lang vs lang comparisons, you should make sure to have good examples of the "other" language. Because after looking at both examples, I still don't understand how the OCaml version is "nicer" other than your point that the compiler warns you about the end of the list.
    You could have done this with a list comprehension, and it would still read like english as opposed to this awkward syntax of OCaml:
    
    l = [1,1,4,3,3,5,8,8,6,4,1,1]
    newList = [item for (i, item) in enumerate(l) if i+1 == len(l) or item != l[i+1]]
    
    From left to right, it reads like plain english. 
    You can even make it a function in one line:
    
    destutter = lambda l: [item for (i, item) in enumerate(l) if i+1 == len(l) or item != l[i+1]] 
    destutter(l)
    
    Or even with line breaks to make it even cleaner:
    destutter = lambda l: [ item for (i, item) in enumerate(l)
                                        if i+1 == len(l)
                                        or item != l[i+1] ]
    
    That still reads much better in plain english as opposed to:
    
    let rec destutter l =
      match l with
      | []                -> []
      | x :: y :: rest ->
        if x = y then destutter (y :: rest)
        else x :: destutter (y :: rest
    
    All I am saying is, its a poor example if you are comparing a bright shiny specimen of an OCaml apple against a particularly withered specimen of a python apple. Or saying that this high end model of car make A is awesome compared to the entry level model of car make B.
    And you also shadow the built-in list type in your function :-)
    
    I would say for an AMAZING static typed, compiled and garbage collected modern language, choose Go  (www.golang.org). Its simple and fast to develop with, has a great standard lib and a large community with many 3rd party libs.
    
  • webreac | Wed, 28 Sep 2011 16:56:19 UTC

    Hello, I love programming languages, I have used caml-light (the ancestor of OCaml) in 1992.
    
    OCaml and haskell have proved their fabulous productivity, but they have not evolved a lot since their conception (AFAIK).
    
    I have the feeling that scala has all the advantages of OCaml and is more modern with fabulous additional features.
    
    Why should I choose the quite old OCaml when scala is available with a so bright future ?
  • Kakadu | Wed, 28 Sep 2011 16:36:45 UTC

    It seems that new lines has been removed (Iceweasel 6 doesn't show it) from code blocks by some reason. PDF version doesn't have such problem.
Leave this field empty

Post a Comment:

(Required)
(Required)
(Required - 4,000 character limit - HTML syntax is not allowed and will be removed)