Looking for Participants for User Survey on ocaml.org Package Documentation and Learn Area

For comparison, this is what the original page looks like:

It may be a better experience to disable Brave’s speed reader mode (https://twitter.com/brave/status/1559235636464418816) for these pages as it is not a high-priority problem compared to more pressing issues.

1 Like

please don’t do that, it will have the same effect “they don’t know what they are talking about”. Memoization is a useful trick in general, Multicore is great technology, I’m just advising against choosing a too simple example, because for this particular example a much simpler and faster solution exist.

(every mathematician knows that a linear recurrence of order 2 can be transformed into a recurrence of order 1 (hence linear complexity) acting on pairs)

For instance here, just use let fib n = let rec loop n = if n < 1 then (0, 1) else let x, y = loop (n-1) in y, (x+y) in snd (loop n);;

Of course, the memoization is also O(n), but it’s like a big hammer when there is a much more elegant solution, and I’m sure ocamlers like fast and elegant solutions :wink:

1 Like

For lightweight concurrent processes (those are provided separately in Domainslib though…), channel communication and message passing, atoms/symbols (well-typed thanks to polymorphic variants!), etc… I think something like erlang’s ping-pong would turn some heads.
The problem is 1. we will have to rely on domainslib, and 2. although I imagine we’re as performant, if not more, than erlang in terms of lightweight processes cost and runtime efficiency (perhaps not scheduling, their runtime is of course more battle-tested), our concurrency prims don’t look as nice currently. There’s more to write by hand than just:

ping(0, Pong_PID) ->
    Pong_PID ! finished,
    io:format("ping finished~n", []);

ping(N, Pong_PID) ->
    Pong_PID ! {ping, self()},
    receive
        pong ->
            io:format("Ping received pong~n", [])
    end,
    ping(N - 1, Pong_PID).

pong() ->
    receive
        finished ->
            io:format("Pong finished~n", []);
        {ping, Ping_PID} ->
            io:format("Pong received ping~n", []),
            Ping_PID ! pong,
            pong()
    end.

start() ->
    Pong_PID = spawn(tut15, pong, []),
    spawn(tut15, ping, [3, Pong_PID]).

so in the end it might not look good from a marketing perspective.

1 Like

I think this implementation makes sense though, fib (n-1) in this definition is roughly “half the work” of fib n.
This implementation of fib is the one doing the most work (of the usual definitions you see around), and also the one with the most visible slowdown, so using it expresses concisely (and elegantly IMO) the idea of “splitting a heavy workload on multiple CPUs”.

It would make way less sense it you were using it for just advertising the language of course, not multicore capabilities.

1 Like

Thanks @hyphenrf, @sanette @benjamin-thomas for the discussion on the playground example. Here’s a PR to improve the playground example by making it clearer that (currently) the point is to show off the new multicore support. Adding the more efficient single threaded implementation in the comment to encourage beginners to think about the performance implications of their code: minor changes to the playground example by sabine · Pull Request #831 · ocaml/ocaml.org · GitHub.

ETA: after the novelty of OCaml 5 wears off, there’s space for a more beginner-focused example to occupy this space.

1 Like

I’m not a specialist of parallel computing, but it seems to me that computation on large vectors (or matrices) is a predilection area. I just wrote a (probably too) simple implementation of a dot product, and on my laptop it’s already quite faster than the sequential loop:

let num_domains = 2

(** Sequential implementation of the dot product of the sub-arrays of
   [a] and [b] of length [l] starting at index [i]. *)
let dot_seq a b i l =
  let x = ref 0. in
  for j = i to i+l-1 do
    x := !x +. a.(j) *. b.(j)
  done;
  !x

(** Dot product of [a] and [b]. Parallel implementation, which simply
    splits the array into [num_domains] subarrays, each of which is
    computed sequentially by [dot_seq], and finally combines the
    results to sum them. *)
let dot a b =
  let n = Array.length a in
  assert (n = Array.length b);
  let l = n / num_domains in
  let rec loop i d spawns =
    if d = 0 then spawns
    else let l = if d = 1 then n - i else l in
         loop (i+l) (d-1)
           ((Domain.spawn (fun () -> dot_seq a b i l)) :: spawns) in
  loop 0 num_domains []
  |> List.map Domain.join
  |> List.fold_left ( +. ) 0.

The tests and results are here: dot.ml · GitHub

I’m surprised that the performance gain is significantly better for bytecode than for nativecode: is there any simple reason for this?

2 Likes

I’m assuming the OCaml playground is for beginners. If so, then it would be tremendously helpful if the OCaml playground example worked on beginners’ computers. For example, the Domainslib used in the example is not generally available for a beginner to use on Windows. Domainslib requires OCaml 5, and that is only available for mingw Windows, which is not something to ask beginners to install.

Someone can correct me if I’m wrong but there is no backport of Domainslib to 4.x (if that even made sense, which is doubtful).

2 Likes

From what I see in other languages and frameworks: Playgrounds serve these purposes:

(1) entice beginners to try out basic examples right in their browser so they do not have to install anything
(2) help people share smallish code snippets in forums/chats in such a way that someone else can help them debug, or
(3) as a way to quickly answer someone else’s question with some code snippet (which is confirmed to run because they used the playground to write it)
(4) for package authors to provide code examples that potential users of the package can tinker with (requires a playground that can import any packages).

1 Like

Oh that makes sense. That is probably why the Rust playground is just a prototypical Hello World example.

Still, have you seen official code examples on a playground where it can’t be run on a large percentage of the viewers’ computers?

My two cents would be:

  • a one-liner program like let () = print_endline "Hello, world!";; by default
  • have a URL parameter for the playground like https://ocaml.org/play?template=parallel-domains-example that can be used in all the OCaml 5 (ex. “Try it now”) pages. Obviously that template URL parameter (or something similar) would control what was populated in the playground, and that is unplanned extra work.
  • the parallel-domains-example could come with a brief comment at the top (* You would need OCaml 5 for this example on a PC. That is available for many platforms at https://ocaml.org/news/ocaml-5.0, with more platforms coming soon. *).
2 Likes

For comparison, the ReScript playground has a tiny React component for their default. Cool thing about that is it shows a strength of ReScript, but is also simple. Now, I’m not sure what the analog of that in the OCaml world would be, but it may be cool to to try and think of some “killer feature” to show off. (Not sure which killer feature, but still worth thinking about.)

A dot product is memory-bound: 1 cold memory access per arithmetic operation. So, increasing the number of domains will not make it faster. Bytecode interpretation, however, is compute-bound. So, you will get a nice linear speedup, until either it becomes as fast as native code execution (and thus memory-bound) or you saturate the cores of your computer.

but I do have a speedup for native code as well.

Keep in mind that, at each loop iteration, your code tests twice whether the array accesses are in bound and whether the domain needs to synchronize with the other domains to perform a garbage collection. Even if all these tests are perfectly predicted by the processor, their sheer amount still mess with the speculative execution, which means that your core does not run as fast as it theoretically could (e.g., what you would get with the same code written in C). So, the memory can keep up, and you still experience a small speedup by going from one domain to two domains.

I am pretty sure that, if you use four domains instead (assuming you have at least four cores), you will not see any additional speedup for native code, while you will still see a 2x speedup for bytecode.

By the way: In case someone who has time at their hands to contribute reads here:

You can always reach out to any of the maintainers on GitHub - ocaml/ocaml.org: The official OCaml website. with a feature/improvement that you want to contribute and we’ll be happy to guide you, pair program, and review speedily. For bigger contributions, do always approach us, because sometimes it is not obvious what exactly is already being worked on behind the scenes.

Not enjoying the content? Wanting to add an academic institution that uses OCaml to the list? Want to post an open OCaml position at your company? You can
(1) fork the GitHub repository, create a branch with your suggested changes and open a pull request, or
(2) open an issue on the GitHub repository, or
(3) send an email. :slight_smile:

In contrast to publishing your own OCaml package, this is a much more casual way of contributing to the success of OCaml: maintenance is taken care of, you can focus solely on improving or adding features and content! :grin:

2 Likes

thanks for the explanation!

Here’s the promised update on what kind of feedback we got out of the user survey. I tried to distill as best as I could, there was so much feedback! :slight_smile:

We have responses from 20 people in total, and a lot of those have volunteered to be interviewed by Claire. So this is excellent! In the interest of getting a good overview of the userbase, Claire will select people and send out invites.

Summary:

17 people are using OCaml for personal projects, 7 for business purposes, and 6 use OCaml for research purposes.

We have a good mix of junior and senior software development and research roles, as well as organisations of varying sizes and a broad mix of tasks people work on. I do not list these individually.

Pain points / package documentation:

Ideas/suggestions package documentation:

  • Tree navigation should be improved, e.g. library vs toplevel module should be consolidated, hiding other libraries when going down into a module should be removed
  • Index for declarations (values, types, exceptions, etc.) of a module could be displayed in place of the empty TOC / appended to the TOC

Problems with content and documentation writing experience:

  • Lack of example code, quality of documentation on package docs displayed on ocaml.org
  • UI/UX of odoc for writing package documentation could be improved
  • hard to incorporate ocamldoc and markdown when writing documentation

Workarounds / package documentation:

  • inspect source code
  • odig, sherlocode.com, opam grep
  • look at package’s tests
  • search in forums, StackOverflow, look for links to package author’s documentation site in package’s public git repository

Pain points / learning section:

  • Layout/scroll problems on https://ocaml.org/doc. People need to scroll too much to see the content. Scrolling down the page does not show the tutorials and guides section, scrolling down the navbar on the left it is hard to scroll down to “common error messages”, “best practices” and “OCaml platform” (Too much scrolling required on the "Learn" page · Issue #850 · ocaml/ocaml.org · GitHub)
  • Accessibility problems w/visual contrast (Add Accessibility-Checking to the Continuous Integration · Issue #835 · ocaml/ocaml.org · GitHub)
  • Difficulty level/prerequisites of tutorials not always clear
  • Lack of important content (e.g. “single-page syntax introduction”, dune and opam guide, task-oriented examples for different levels of language learning)
  • Styling difference between manual/stdlib API and main pages
  • “Standard Library API” link goes to the index instead of to Chapter 28 of the OCaml manual (manual gives a more adequate introduction to the standard library for beginners and does not expose internal functions like the automatically generated index does)
  • Problems with outdated information

Pain points overall:

  • Site doesn’t motivate people enough to use OCaml by showing how OCaml is cool, interesting, nice to use and how using it makes you a better programmer

Ideas/suggestions learning section:

  • The more basic sections, e.g. if statements, pointers, could be merged or made collapsible to make it easier to see all items on the side navigation
  • “Papers” section is not so relevant to most OCaml beginners and should be moved below “Books”
  • Have a “beginner”/“advanced” toggle at the top of the learn page that switches the content area to be tailored better to the different use cases
  • add more context on who should read a particular book (e.g. prerequisites, topics covered)

Workarounds learning section:

  • directly go to the manual
  • books, blogs, other sites
  • ask on forum/discord/StackOverflow
  • check ocamlverse

Tbh, this took a bit longer than I thought: there is so much useful info in your feedback! I want to add links to corresponding issues, but this will have to wait until I edit this post tomorrow.

10 Likes

Thanks! here is another suggestion:

when odoc builds documentation, the “type” or “val” keywords are displayed strongly (boldface), whereas the information it provides, while being theoretically important, is of very little use in practice compared to the particular name of the value or of the type.
In fact, the name of the value/function/type should be much more prominent, in my opinion (this means also compared to the signature of the function). This is what most other languages docs do. I just made a comparison test for this:
compare:

  1. an “improved” version of standard odoc output:
    Plt (oplot.Oplot.Plt)
    and
  2. the “ocaml.org” version:
    Oplot.Plt · oplot 0.71 · OCaml Packages
3 Likes

Thank you, this is a great comparison! Here’s a quick patch minor improvements to package docs odoc styles by sabine · Pull Request #884 · ocaml/ocaml.org · GitHub. After upgrading odoc on ocaml.org we can tweak a bit more.