I am in a state of transition: from Java to OCaml.
I like Java as a platform primarily for its matureness, static typing, and great IDE integration (Netbeans in particular). But lately I’ve been finding myself manipulating a lot of tree structures—ASTs, query plans, nested relations, automatically generated GUI layouts—and Java is just too verbose. Even using visitor patterns, the real application logic just gets too diluted among classes, methods, and variable declarations to help me gain any additional insights from the coding experience. I find this unacceptable, as one of the main reasons why I code is to solidify my understanding of otherwise theoretical ideas. It was time to move to OCaml.
Well, I only had experience with SML (a dialect of ML) from compiler and programming languages classes and a few smaller projects during undergrad, but I knew that sum types, pattern matching, and strong static inferred typing just might be what could fit 4000 lines of Java into 500 lines of functional goodness. OCaml turns out to be the more popular (and less obscure) dialect of ML, so it seemed like a good choice. I was concerned about tool integration, however.
I took it for granted that OCaml would force me to give up the many great IDE features I had been accustomed to with Java and Netbeans: code completion, editor/build system integration, live documentation browsing etc. Especially since I’m a Windows user (on the desktop, anyway), I had serious concerns about whether I would be able to set up a satisfactory work environment with OCaml. To the rescue came F# .NET, or so it seemed.
F# is Microsoft Research’s new adoption of OCaml for the .NET environment. In essence, F# is to OCaml what C# was to Java, and one of its big selling points is integration with Visual Studio. Excited, I bought Expert F# (a very good reference book, which I will use even as I learn OCaml) and downloaded the F# May 2009 Community Technology Preview for Visual Studio 2008. I spent the next two weeks trying to learn and set up the environment to suit my needs, which included parser generation using fsyacc/fslex and heavy use of the F# interpreter to debug my code.
Unfortunately, F#’s Visual Studio integration is to this date rather rudimentary. I understand that the plugin is still in early development, and I’m sure it will improve a lot in the next year or two, but meanwhile, here’s a quick grief list:
- No syntax highlighting or code completion in fslex/fsyacc source files. (While parser generation might be seen as an obscure feature on any other platform, ML people do have a striking tendency to be compiler researchers or language designers…)
- The FsYacc/FsLex MSBuild tasks do not consistently generate new parser/lexer files after the definition files have been modified, and a “clean” operation does not delete the generated files.
- Console apps (e.g. “Hello, World!”) open in a new window which promptly disappears after the end of execution, instead of having their output routed to a console output window. Visual Studio might be a little weird in general here, but I couldn’t figure out how to fix it.
- There is no easy way to use the interactive console in the context of the code that is being built in the current project. For instance, if my project code defines a number of modules, namespaces, functions, and data types which are all compiled into a DLL, I would like to always be able to access the most recent build of those definitions from the interactive console, without too much fuss (see below). Automatic copy-and-paste of raw source code into the interactive console does not do the job when you have multiple files (some possibly generated as part of the build process) and when you don’t want old definitions hanging around.
Currently, a single iteration of interactive testing would involve the following steps:
- Make a change to the source code.
- Manually delete fsyacc/fslex-generated files to make sure they are remade on the next build (see above).
- Reset the interactive console (step 5 below will lock up the output DLL, causing the build to fail if we don’t do this).
- Do a build.
- Issue a command like #r “Z:\\Unfinished\\EverythingCO\\trunk\\fswork\\qllib\\bin\Debug\\qllib.dll”;; to make the compiled definitions available from the interactive console.
Add this to the fact that the F# language itself is still bleeding edge, and the costs to productivity start outweighing the benefits. So for now, I decided to abandon F# in favor of OCaml, spending yet another two weeks trying to set up a great work environment.
And there it was. With Eclipse plus the OcaIDE plug-in (and Cygwin to provide some underlying prerequisites like make), I found everything I wanted. It took a little while to figure out, but in the end I had:
- A Makefile-based build system which would not only work on my own Eclipse/Windows environment, but also for anyone else who might like to check out the code in the future, for instance on Linux. The plug-in has a centralized Preference page to set up all the necessary OCaml paths. Note that the build system I use is just the standard OCamlMakefile—other options are available.
- Code completion and object browsing.
- Syntax highlighting in ocamllex/ocamlyacc definition files (though no code completion in ocamlyacc semantic actions.)
- Automatic rebuild every time I save a file (standard Eclipse stuff).
- Compilation of custom OCaml toplevels, giving me the kind of interactive development I mentioned above (though you still have to manually kill the existing custom toplevel before rebuilding).
- Console app output shows up in a console (compare above).
This, together with the matureness of the OCaml language, has made me choose OCaml over F# for now.