What I dislike about OCaml

Are the plans to add a machine-readable format for compiler errors?
It will help with editor integration if nothing else.

1 Like

It’s already there if you use LSP. LSP gives you error messages and much more :slight_smile:

2 Likes

There is an in-progress PR implementing the basics of JSON output for compiler messages. One reason it is not making progress is that there are in fact few interested users of the feature – most projects that are programmatically calling the compiler already have worked around their own way to do this, and do not seem so interested in rewriting their code to use a new approach or even in giving us clear feedback on what they need.

2 Likes

For the JSON-formatted error messages, I had some feedback that at least @rgrinberg and the lsp-server would be interested, at least partially to have an easier way to segment error messages in submessages.

That would be a start. As of today, editor tooling has the following requirements from error messages:

  • The ability to extract sub messages and their locations
  • Preserve formatting metadata. That means NOT rendering boxes, wrapping, colors.
  • A way to identify the type of the error without parsing the error message to offer users context specific suggestions on how to fix the error.
  • A way to compare two errors for equality to deduplicate errors coming from dune and merlin.

I hope this feedback is clear enough as to what our needs are.

I shared my take on the very problematic nature of this POV not too long ago:

There is so much we want to do: to improve our community, to further the development of our common language, to build out our tooling, to make our culture more inclusive and inviting, to strengthen its mutualistic connections with other communities… So much to do, and so little time in this fraught world.

Having granted that there is very much to do to nurture the OCaml ecosystem and confirming that it is well worth doing, I’d also like to remember that successful technology and communities ought not have size or popularity as their primary measure. There are many amazing technologies that provide high value in very particular niches (to name a few Prolog, Z3, Mirage) and there are many healthy and vibrant communities that do not end up becoming massive trends and contending domination in the world mono-culture (and I’m not sure how healthy the communities are that do end up contending thus).

I was inspired to add this delayed reply by the following photo of a slide from RustConf:

https://pbs.twimg.com/media/FZaa6ObUEAEEED_?format=jpg&name=large

11 Likes

IME when people say ‘think of it like a product’ what they really mean is ‘think of the UX/DX’. If we were actually thinking of it as a product we would be asking what’s the marketing budget. What we’re actually talking about here is how easy or difficult is it for people to use? Of course after spending enough effort and training on something, anything can become easy. But what’s the activation energy required to get started with the OCaml toolchain? That’s the critical question.

2 Likes

They mean something more: they really mean “think of the UX/DX for newbies”. And sure, that’s important. But (for instance) I’m not actually very impressed by Rust’s Cargo. I mean, it’s a single unified tool, sure that’s great. Which means that it incessantly (and I mean incessantly) recompiles dependencies. Every damn time I switch from cargo build to cargo bench or maturin develop (I develop a lot of code that gets wrappered by Python and maturin is the tool for that – gosh, more than one tool! Get me my fainting couch!) it recompiles everything in sight.

I much, much prefer the split between opam and whatever per-package build-tool you use (I prefer Makefiles to dune – don’t @ me unless you’re ready to bring your A game). And maybe there are some problems, in which case, sure, show 'em, maaaan.

To go back to a refrain from my Golang comment elsewhere: none of us actually knows what big companies that use these languages do for tooling. But we know that (for instance) at Google, they use bazel (called “blaze” internally), and that it’s very different from all these other build-tools. It’s great, just great really, to provide these little shiny toys for newbies to use. Sure, great, have at it, kids. But I’m a professional, and I don’t build toys. So I want professional tools, and professional tools scale to large projects and to complex multi-language projects. A package/build-system that doesn’t allow me to step in and do that, is going to get in my way.

I actually think OCaml’s opam/dune design is excellent in this regard.

6 Likes

And that’s exactly the problem. Simple things are difficult because the tools insist that they want to handle large-scale use cases from day 1. They force the newbies to have to care about the things that the experts care about. This is not a great UX.

Forget about Rust for a second. Look at Go’s UX. I do go mod init to create a project, just start importing and using modules in my source code files, then run go mod tidy to download, cache, and checksum them all in one shot. And it even works beautifully for reproducible builds and CI from day one, because it produces a go.sum lockfile with not just the versions but also the hashes of all the used dependencies. I don’t have to worry about opam files, dune-project files, dune files in each directory, and trying to figure out how I’m going to set up switches and lock the dependency versions.

I’ve said this before but I really think we can learn a lot from Go’s tooling and attention to supply chain security. I wouldn’t even mind a build system that forced me to declare my library dependencies at the top of each OCaml source code file.

EDIT: I’d even go further and say that, in retrospect, tools which try to cater to primarily expert use cases are taking the wrong approach. Experts will just use findlib and Makefiles, as you yourself have proven. The whole point of tools like this is to cater to non-expert use cases.

2 Likes

This is a fair cop. But I would add that opam does an excellent job of managing package interactions and evolution. I had a bad experience with Rust early-on, where some Rust package C depended on B, which depended on A, in ways that made B break when A got a new release. This was pretty unpleasant, and what was more unpleasant is that there was no way to force the version of A selected, to be a backlevel one.f

The opam maintainers and their discipline (which they enforce on all of us) makes the opam repository the closest thing I’ve ever experienced, to a massive mono-repo.

That’s valuable, and I wouldn’t want to give that up. Having experienced Rust’s “crates”, I’m even more adamant on clinging to the stability of opam-repository.

3 Likes

I understand the approach they’re taking but it’s funny to praise this approach while also praising how scalable the tools are. The hand-curated opam approach will have a tough time scaling to even a moderately-sized project that needs to control its dependency graph. Right now the best advice on offer is to vendor the entire dependency subtree into the project directly if you need to customize anything.

Well, let me just point out that this isn’t actually as straightforward as it looks. Sure, I’m perfectly happy that the unwashed use dune. Great, great. But when I was writing my camlp5-based work-alikes for all the standard PPX rewriters, I found that it was well-nigh impossible to figure out from the documentation, how to invoke them directly. Sure, you could do it thru dune, but I wanted and needed to do it thru Makefiles. I had to reverse-engineer how to do it by inspecting the (ridiculously verbose) build log.

If I could ask one, only one thing of dune, it would be to map their libraries and other large-scale build-artifacts to findlib packages, so that those of us who don’t use dune could interact with dune-based builds. Instead of having to rip out dune and redo everything.

When starting to use OCaml I found https://ocamlverse.github.io/ really, really helpful. For example, like others have said I was distracted by having to choose Base or Containers or pure Stdlib, but Ocamlverse gave me a good overview and guidance on that. I’ve found the same on other things like web servers and database libraries. And the information was pretty up to date.

So I think it’s extremely worthwhile to maintain Ocamlverse and it seems like it should be more prominent. I can’t find a link to it from ocaml.org. Is there some reason it is separate, or it just happened that way and there hasn’t been time to integrate it?

The other complaint that resonated with me is the lack of library doc. It’s true the code is very readable, but I think everyone (beginners or not) would benefit greatly from good library doc, including at least a minimal example, for each function. Some Ocaml libraries are good in this respect but a lot are not. I suspect this is a cultural thing – once it becomes acceptable to leave out the doc, people will do it. The only way to change that is to make it unacceptable by example and peer pressure. Is that worth it?

7 Likes

I’ve said this before but I really think we can learn a lot from Go’s tooling and attention to supply chain security. I wouldn’t even mind a build system that forced me to declare my library dependencies at the top of each OCaml source code file.

I wouldn’t mind more explicitness either. Even having to declare, in one
file per library, the list of modules in a OCaml file, and having to
import them? That’d be quite neat and clean. Currently you just find
modules that are magically in the namespace :confused:

2 Likes

This “vendorizing” is precisely what got those Rust modules in trouble. The Rust approach is to “automatically vendorize” when deps can’t be met without it. So when package B exports types from package A, and package C needs a different version of package A directly, you can end up with types from both versions of A visible, and no way to prevent it.

I’m 100% OK with a package-writer deciding to vendorize. I am adamantly against a package-manager that automatically does so without the package-writer’s knowledge.

2 Likes

Yeah, and in fact many beginners don’t like how magical the implicit imports are, they prefer explicit imports! It would even solve 90% of the namespacing problem. E.g. imagine:

(* test.ml *)

#depend "decimal";;

let s = Decimal.of_string

I believe something like this will be possible with Bazel modules, which I hope to support in OBazl 3. The tricky bit is making it work with legacy libraries. I haven’t figured out how to do that yet.

2 Likes

I’m curious about this. A lot of OCaml beginner struggles are made easier with support from your organization, but here you are saying you’re forced to use it? Are you the first person in your org assigned to carve out a path here?

4 Likes

I came across the discussion and I wanted to share my newcomer perspective. I’ve started learning OCaml only a couple of months ago, but I do have experience with various FP languages (e.g. Clojure, Erlang, Elixir, Haskell, Scala).

Yeah, the rant was poorly written and rants generally serve little purpose, other than venting out. While you can’t please everyone I do think that some of the points about the experience of beginners make sense. I’ve started to play with OCaml recently after seeing some people I know from the Clojure community endorse/praise it here and there (e.g. @cemerick, who has always been one of Clojure heroes). My initial impression of the language is quite positive, but like many others I was somewhat put off by RWO leaning heavily on the Jane Street libs. I understand that some of the authors work at Jane Street, so I totally get their perspective, though - after all that’s how they do OCaml in the real world.

I also went over much of the Cornell course, which is good, but it’s clearly geared towards students (who does formal verification on the job? ). There’s clearly space for more entry-level books/resources on OCaml. If that wasn’t the case we probably wouldn’t be spending some much discussing the choices made by one particular book.

Syntactic preferences aside (like everyone I can bikeshed all day every day on trivialities), my only real gripe with OCaml so far is the small scope of the standard library - e.g. dealing with unicode strings and regular expressions in our day and age should be easy right? These days the expectation of most people is that a language comes with batteries included and plenty of great languages have “failed” because of this (e.g. Common Lisp, Scheme, etc). People are lazy and don’t want to reinvent the wheel all the time.

The OCaml tooling is an area where many people complain about, but I found it okay overall. Yeah, dune and opam don’t have the best docs, but they are relatively similar to what you’d find in other langs. Merlin/OCamlLSP provide adequate support for most editors. I even quickly hacked a few small patches for utop.el, flycheck-ocaml and tuareg-mode, as Emacs is my programming fortress.

Still, I was quite confused for a while what the hell is esy, jbuilder, etc. The relationship between OCaml and ReasonML definitely adds some complexity to the ecosystem. The more you read and practice the more you know and the pieces of the puzzles slowly get into place. Most people probably are not willing to go that far.

Third-party libs were also a mixed bag for me as I’d often notice libraries with little document or concerning little dev activity (e.g. the popular Dream framework).
I’ve been in plenty of small/fringe dev communities to not be super bothered by this, but I guess that’d be much more concerning to people who have spent their time mostly in the “mainstream”. Half my friends were telling me that learning OCaml in 2022 is a complete waste of time, as I already know to a different extent half a dozen FP languages and Haskell in particular is quite similar. Still, I don’t regret the time I invested in OCaml so far and hope to get even further with it. There’s a certain air of simplicity and pragmatism around it that I really like that reminds me from time to time of my beloved Clojure. I don’t like dogmatic languages, I like languages that help me solve a wide spectrum of problems

21 Likes

I agree, it should be easy. However, I think that the way this is supposed to be made easy in OCaml is to have an easy way to depend on something, and I think the OCaml story on that is quite good. Batteries not included, but the battery store is really convenient if you want. It still could handle improvements, but the choice of not putting to much stuff in the stdlib is reasonable in my opinion.

3 Likes