What are the biggest reasons newcomers give up on OCaml?

As chance would have it I’ve done just that recently. My daughter needs to apply to some sixth-form (17/18 year old, UK) colleges and I tinkered with a little web-frontend to some downloaded data. I’m just experienced enough to dig my way out of the little problems I encountered, but not so experienced that I don’t make them.

I tried out dream-html because I saw the author had mentioned it recently in this forum. The main package page dream-html 1.2.0 (latest) · OCaml Package says there aren’t any docs (as of 2023-09-05) whereas if you click through to GitHub - yawaramin/dream-html: Generate HTML markup from your OCaml Dream backend server then you get a nice README with examples and everything.

HTML tags in dream-html are basically used as tagname [list of attrs] [list of child tags] with some suitable type constraints to catch basic errors. That all worked as well as you could ask until I had to do something a little unusual.

textarea [ id "notescontrol"; name "notes" ] "%s" c.notes

You’ll note that there isn’t a list after it - there is a just a format-string and value because textarea doesn’t have nested tags. Took me a few goes to get that though. If you get that wrong and put a a list in then you get this.

File "bin/main.ml", line 292, characters 53-70:
292 |       textarea [ id "notescontrol"; name "notes" ] [ txt "%s" c.notes];
                                                           ^^^^^^^^^^^^^^^^^
Error: This variant expression is expected to have type
         ('a, unit, string, node) format4
       There is no constructor :: within type format6

Now, I’ve seen errors about “formatX” before and know it’s because of some fairly complex stuff that must be going on to allow format strings to be type-checked. But - that error does not say “you put a list here and we don’t want that” - not unless you already know that is what it means.

As luck would have it, the library not only has docs but also an understandable test-file and is (to my beginner eyes) clearly written.

let textarea attrs fmt = text_tag "textarea" attrs fmt

Ah, of course! It doesn’t want a list of nodes for a textarea - just a string literal or a format-string and value.

292 |       textarea [ id "notescontrol"; name "notes" ] ("%s" c.notes);
                                                          ^^^^
Error: This expression has type string
       This is not a function; it cannot be applied.

I actually did this. I was misled by the fmt and thought “single thing - I’ll bracket the format+value to indicate they go together”. Here I run out of instincts that can help me. The fmt must be getting expanded inline in the list of arguments but it isn’t its own thing even though it has a name.

Interestingly, in vim if I correct the error and then highlight "%s" c.notes and look up its type it gives me the same error-text.

So - the issue here I think is that someone with 20+ years of experience can very quickly fall off a cliff with something that should be trivial.

The second significant issue I had was with caqti. I have used it before (very minimally) so can copy and paste working examples for some basic queries. I’d not done an update before though, and knew I’d have to change the infix used. For example, the multi-row operator is ->* and the exactly-one-row is ->!. So, I type “ocaml caqti” into google and get the github repo as the first result - the README doesn’t seem to cover this and doesn’t link to anything that does. I’ve seen these operators listed somewhere though. Second result is opam - caqti which I realise is the old package list. OK, go to ocaml.org and search from there. “No Docs” for the current version of the package, select a slightly older one and that has a docs button.

Except… no actual docs (AFAICT) - mentions dependencies on things like “ptime” but just lists two top-level libraries. Now I knew I’d seen lots of docs for caqti, but they just don’t seem to be linked from anywhere.

Eventually I managed to get to Infix (caqti.Caqti_request.Infix) but I still have no idea how to actually navigate to that by following some top-level links. The “Caqti API Reference” from the github page must lead there somehow.

So - I don’t know exactly what isn’t right with docs searchability but it wasn’t bringing me much luck.

And finally, this is what dune fmt does to my database-interface code.

let db_college =
  let encode
      {
        urn;
        laname;
        schname;
        postcode;
        schstatus;
        schooltype;
        agelow;
        agehigh;
        gender;
        relchar;
        all_he;
        all_russell;
        all_oxbridge;
        home_postcode;
        mins_from_home_postcode;
        rating;
        notes;
      } =
    Ok
      ( urn,
        ( laname,
          ( schname,
            ( postcode,
              ( schstatus,
                ( schooltype,
                  ( agelow,
                    ( agehigh,
                      ( gender,
                        ( relchar,
                          ( all_he,
                            ( all_russell,
                              ( all_oxbridge,
                                ( home_postcode,
                                  (mins_from_home_postcode, (rating, notes)) )
                              ) ) ) ) ) ) ) ) ) ) ) ) )

and

  let _query =
    ((int & string & string & string) ->. unit)
    @@ "INSERT INTO college_notes\n\
       \        VALUES (?, ?, '?', ?)\n\
       \        ON CONFLICT (urn, home_pc)\n\
       \        DO UPDATE SET notes=?\n\
       \        WHERE urn=excluded.urn AND home_pc=excluded.home_pc"
  in

Marching off the right-hand side of the page is the sort of thing I expect from a corner-case with a code formatter. But mangling my queries and rendering them un-copy-paste-able because I dared to let them extend over more than one line? That’s not much fun.

So:

  1. You fall off a cliff-edge when you hit a slightly-more-complex error.
  2. When docs are there, they don’t seem to be easily findable.
  3. There is a difference between reformatting code and messing with my string literals and I don’t appreciate the second one.

None of this is to do with the complexities of handling lwt + caqti themselves and how that interacts with dream as the web backend. That’s no fun, but I understand what it is there for even if I don’t have any valid instincts for it yet. These three are just zero-benefit things. They aren’t anything to do with the program I was writing - just useless bits I had to get right to get the program to run.

15 Likes