Dune pain point: the language design

We have recently been discussing OCaml pain points and dune came up a lot. I thought I would add a point which came to mind: the design of the dune configuration (s-exp) language. My critique is not what you might be thinking–although an s-expression syntax is a bit of an odd choice, ultimately it’s not a showstopper. The problem I am having is that the language itself is just not very well designed.

For example, the dune language allows describing various components:

  • library
  • executable
  • executables
  • test

This means we can have (library ...), (executable ...), etc. stanzas and they share various common fields like (name ...), (libraries ...). The problem is that this makes it difficult to talk about and effectively describe the dune file contents to people. When they ask how to add a library dependency, we have to say ‘add it to the (libraries ...) field in your dune file’s (executable ...) stanza, or the (library ...) stanza, or whatever stanza you have’. Sure, we can say ‘add the (libraries ...) field to your component’s stanza’, but ‘component’ is such a generic name that no one will remember what it is.

If the components were all described by a (component ...) stanza:

(component
  (name main)
  (type executable) ; or library/test/etc.
  ...)

We could just say ‘add the (libraries ...) field to your (component ...) stanza’.

I see a couple of other places where the language could be improved, but I won’t make this post too long right now. My 2c.

3 Likes

Do you mind expanding on what advantages your scheme brings? To me, it doesn’t make much of a difference to say “add x to the libraries field of your executable” vs. “add x to the libraries field of your executable component”. Seems like it’s just a bit more verbose this way without much compensation. Maybe I’m missing something. Would we also have components for other stanzas? such as rule, cram, etc?

I’ll give some motivation for the current scheme though. It maps rather naturally to a type like:

type stanza =
  | Executable of ..
  | Library of of ..

There’s usually an understanding that different constructors of a type take different arguments. The same applies for stanzas and the fields that they accept.

I am not sure I agree with the proposed syntax, but

type stanza =
  | Executable of {name: string; libraries: string list; ...} 
  | Library of {name: string; libraries: string list; ...}

can be rewritten as:

type kind = 
  | Executable of ..
  | Library of ..

type = {name: string; libraries: string list; kind:kind} 

Its a pattern I have used quite often. However I think its more useful when you have to do things like “query the name” often which is not the case for a dune user.

1 Like