There’s actually an OCaml plugin for IntelliJ, but afaik it’s not at the level of support that other languages have. I primarily have experience with Scala in IntelliJ IDEA, and the things I benefit most from are:
Automatic imports. The OCaml equivalent would be automatically adding a library to a dune file when I use its module.
Jump to definition. We have this already, but only one level deep, and beyond that we are told to vendor libraries, which is not really satisfactory imho.
Type and docs on hover. We have this and it’s quite serviceable. There’s maybe some room for improvement.
Project-wide refactors like renaming. This is not really at the same level, e.g. if I change a name in the implementation, it’s not changed for me in the interface. Sure, the compiler catches this, but a best-in-class IDE does it.
Autocomplete. We mostly have this at the module level. One big problem is still that typing in autocompletes as in_channel, and it’s needlessly difficult to stop that.
Opening a browser with library documentation. This should not be very difficult, all the basic pieces are there.
Anyway, this is not to make demands but rather to talk about the remaining gaps which, of course, we hope will be filled with time. If I can say one thing though–imho all of the above are more important than even sophisticated debugging support, and then typed effects and modular implicits. They are also unfortunately much more boring
My vote is for typed effects. Typed effects are by far the most interesting and novel feature that might really distinguish OCaml from the rest of the pack.
I’m also quite worried about this “in between” state we have with untyped effects and pray that the transition to typed effects isn’t too disruptive.
Having said that, modular implicits are kind of needed to equalize OCaml to Haskell’s and Scala’s type classes.
Regarding the desire for a better debugger, I’m in the category of never actually needing it. In fact even now as a python programmer professionally I never once had to reach for it. I would put this at the bottom of the list, frankly. Both Python and OCaml have great repls (not to mention jupyter notebooks) for interactive or exploratory work in practice.
Jump to definition. We have this already, but only one level deep, and beyond that we are told to vendor libraries, which is not really satisfactory imho.
I think the dune package management work will make this easier to solve. Hopefully once that is released we can offer a similar experience to vendoring.
Project-wide refactors like renaming. This is not really at the same level, e.g. if I change a name in the implementation, it’s not changed for me in the interface. Sure, the compiler catches this, but a best-in-class IDE does it.
Project-wide stuff is still hard, but it’s getting closer. There’s been recent work on global find-references in merlin, and when that lands I think global refactorings like renaming will be somewhat easier to build. Unfortunately, OCaml’s module system makes renaming a surprisingly tricky refactoring to implement in general (see Academic Papers -).
Opening a browser with library documentation. This should not be very difficult, all the basic pieces are there.
I’ve been looking at implementing this in ocamllsp.
re: multicore. One thing I’ve noticed in programming with both “green threads” and “native threads” is that once you get a program of sufficient complexity, the bugs aren’t so different. Looking at a line of code, you can’t really tell whether it’s going to be suspended in the middle while some other “thread” runs. I mean yeah, sure, for simple programs you can tell. But not for anything complex.
I remember working with a Python “eventlet” (== “green threads”) implementation (hence, running on Python’s GIL) that ran on a single “native Python thread”, and yet, with a complex program it was pretty much impossible to reason about it in terms of the blocks that ran without interruption. I made the joke (at the time) that you had to assume that the newline character invoked a possible (again, green-thread) context-switch.
Re: logging. In Java, when I wrote my first Java web-app server for the 1996 Olympics, I used a little syntax trickery to hide the log-lines in comments that got expanded before compilation (and then contracted, so the source remained as the programmer wrote it).[1] I’ve also written aspect-oriented code-injection tooling to inject log-lines into Java code en masse (as in: "instrument every method in these classes, that match these regexps). In OCaml when I build complex concurrent systems, I use bolt/volt for log-lines. Those log-lines aren’t invoked unless they’re enabled at runtime, so they’re cheap enough to simply leave in the code.
For simple debugging, I find that you first get a reproduction of the bug in a toplevel, and then start adding #trace directives to get closer and closer to the bug. That’s been pretty much enough to debug, since the days of caml-light in 1991.
[1] the expanded code was all on the same line, so that line-numbers remained the same. Java’s decision to eschew a preprocessor and #line directives was proof that they designed the damn thing in a hot tub while high on pot.
We can already do odig doc mypackage in the vscode terminal which is very little effort.
I agree though that it would be slightly nicer to do it by rightclicking the module name or whatever, all the more that if it is supported directly by ocamllsp or by the extension it should make it easy to ensure you use the right switch, which can be a problem in the terminal.
Just to clarify some more, I’m currently in the mindset of “how to make a company start using OCaml”. If I go to my manager and push for OCaml, and then tell him there’s no easy way to run a debugger on it , he’ll laugh me out of his office. OCamlEarlyBird is a good direction, but the effort needs to be made IMO to get to full gdb debugging with DWARF. We simply cannot compete with other languages (even Haskell!) without it in the corporate space.
Regarding some of the other things mentioned:
Modular Implicits: Requires many years of research. We need to let go of this one as a community.
Typed effects: extremely important, but also requires quite a bit of research, and OCaml’s research bandwidth is quite limited. I’m not sure when we can reasonably expect it to land.
Regarding debugging highly concurrent code: even with OCaml 5.0, most OCaml programs will not be concurrent. For non-highly-concurrent code, debuggers are the most efficient method of debugging.
Very much a newbie in OCaml and not paid (sadly) to write any. But my $0.02 is also that an easier story around debugging would be a boon to adoption. While I appreciate the points raised for how workarounds exist, I have relied heavily on debugging in every job I’ve had. It’s not the only tool in my toolbox, but it is an important one, and I feel hindered by its absence in OCaml.
I’ve debugged native embedded devices (over JTAG), mobile, desktop and web applications (front and backend) and having it has always made me much more productive at finding and fixing issues. I’ll also add, that many times I was debugging multithreaded code and disagree with the notion that it provides no value there. I’m sure it depends on the architecture, but I distinctly remember allowing a touchscreen driver thread to continue running while setting breakpoints on the thread that read the higher level touch events out that queue. So just because there are threads and simultaneous execution doesn’t mean one has to always give up pausing.
I might have the minority opinion on this but I’m not excited at all about implicits, rather worried. Explicits are a strict improvement and I would love to have them around… Implicits… not so much.
I have fear of hopping on discuss few years down the road from now and finding many discussions on “type taxonomies” and news of efforts to create libraries/apis solely to mirror category theory concepts.
Worse, I fear this attitude will find its way to popular libraries and they’ll stop being straightforward to use because their authors felt the need to subscribe to high abstraction hierarchies.
I like that the module language is syntactically heavy. Anecdotally, a friend of mine noticed this on a project they wrote in both rust and ocaml, they noticed they only implemented the functionality they needed in ocaml, while spending a lot more time “playing type-tetris” and writing abstractions then instances/impls of those in rust. Less churn is always good IMO.
Yeah having automatically resolved Eq and Ord and Show and Conv would be cute, but I’m really pessimistic about the loss in readability and the encouraged abstraction hell.
We had a thread here recently where after a lot of back and forth, I think everybody was on the same page that most of the deriving issues completely go away if we have just one PPX that derives a high-fidelity, introspectable runtime type from the static type. This allows library developers to create simple converter functions for every conceivable kind of format, without needing to implement a PPX for each one.
[…] just one PPX that derives a high-fidelity, introspectable runtime type from the static type. This allows library developers to create simple converter functions for every conceivable kind of format, without needing to implement a PPX for each one.
I apologize if this is off topic, but my answer to the original question (as a distant observer who uses elixir and elm and plans on using go or python next because I enjoy early stage startups, although I have used Haskell, scala, and some rescript in the past) is:
crud ecosystem
Finish out Dream, if it is missing any other features critical for production use.
Finish making a feature complete alternative to ecto or sql_alchemy (supporting just postgres would be sufficient)
At that point, I don’t see much holding commercial adoption back besides momentum/time.
It’s worth noting that Haskell has a lot of trouble with their LLVM backend. LLVM has zero backwards compatibility, which means you have to vendor it to have stability.
As for me, I would appreciate ad-hoc polymorphism first, and then a good debugger. In particular the print function would be much more convenient with ad-hoc polymorphism (no more print_xyz for any type xyz). I like Swift’s approach which supports arbitrary types in print “value = \(expression)”.
Regarding the debugger, since GDB support would mean much work to realize, I would suggest to consider a web-based bytecode debugger written in pure OCaml since all bytecode is supported by js_of_ocaml. A web based debugger could provide platform-independent remote debugging as well as graphical output of data structures.Such kind of a debugger could also provide plugins written in OCaml to extend functionality.
P.S.
With “web-based bytecode debugger” I mean a source-level debugger based on bytecode. A native version could also be possible with WASM but that would be another task with too much effort (IMHO).
Explicit ad-hoc polymorphism should be pretty easy to realize (in contrast to implicit ad-hoc polymorphism with automatic type conversions). So far, if I write let f (x : Int) = … and then let f (x : String) = … the second f overwrites the first f. With explicit ad-hoc polymorphism just all functions f defined so far (and only those!) would be available. The compiler would just need to choose the right function f with appropriate type, and quit with error if there is no explicit function f for a given type.
As a user of earlybird, it’s fantastic. Do i need it often? Nah, but when it’s available it’s very helpful. Lots if opaque types reported tho, which would be great to de-opaque-ify. Some recent patches landed for 5.x, which im yet to test.
The next priority should be getting OCaml on Windows into a good state, where you can reasonably opam install something and expect it to work. Many of the pieces are coming like opam 2.2 and Windows support for OCaml 5.0/5.1, then the next piece is getting everything build on Windows or providing Windows equivalent libraries.
For actual language features, I’d like to see typed effects, wasm and modular implicits in roughly that order.
This has definitely drifted far off topic, but while that roadmap (i.e. the churn to eio and untyped effects) is activity, I think it’s fair to say that its completion doesn’t necessarily represent a “finished” state.
Insofar as web development is a priority for OCaml-land, I would personally be looking for stability and reliability in depth from the available web framework(s) vs. any other set of priorities.