I’m going through this right now, and I have found it a pretty rough landing, to be honest. Which is very understandable for a new language pre-1.0, but I thought my “beginner’s mind“ experience might be insightful/useful.
The first thing is that when I go to the standard library documentation, I land on a list of types and namespaces without explanation. Without some sort of preamble explaining the organizing principles behind the standard library, I have to come up with my own hypotheses by inference. My first, and mostly unconscious, assumption is that these two things (types and namespaces) will be mirrors of each other, especially when I see ArrayHashMap and array_hash_map. It then requires cognitive effort to disprove that hypothesis (taking a look at both and keeping something in my so-called “working” memory
), and until disproven the hypothesis is actually a drag on my rate of learning.
I’m the type of nerd that likes to read the documentation from start to finish, (and also the kind of nerd that is easily distracted
). When you are trying to take in an entire language/framework/runtime/etc to build a nebulous mental schema of it’s possibilities, it really helps when the documentation contains a lot of examples AND each big idea/category has its own introductory preamble explaining the concepts in each section (documentation is a tree after all
). Longer term, I suspect those preambles would also help new contributors land their changes in the right areas and reduce some of the discussion-induced maintenance burden.
So while a description of each big section/namespace helps newcomers build strong branch nodes in their mental schema to which to attach new learnings, having lots of examples in the documentation helps immensely with discoverability.
This was something I actually thought Deno did quite well recently – their documentation is basically structured in three parts:
- Introduction + Fundamentals, which can be read relatively quickly (maybe 1.5hrs?)
- Examples, which are immensely helpful for discoverability
- Reference, which is pretty analogous to the current zig std library documentation. However, I will say that comprehensive explanations are a bit hit and miss throughout their reference documentation, e.g. this one provides a great explanation of why you might use it and the principles behind it, while this one simply describes what the name means but not what it does. I’ll go through a reference document like this and read every instance of the former example – then when I run into a problem I don’t yet know how to solve, I get a spidey tingle that there’s something useful in the documentation.
I found I couldn’t read the standard library documentation front to back like that – I tried, and I will probably try again sometime.
The other thing I personally find really helpful with documentation it is when it’s written in active voice describing how (and why) to use it. For example, this is the current description Io.Queue:
Many producer, many consumer, thread-safe, runtime configurable buffer size. When buffer is empty, consumers suspend and are resumed by producers. When buffer is full, producers suspend and are resumed by consumers.
Whereas, in my opinion, I would find it easier to understand if it were something like
Use an Io.Queue when you need one-or-many threads each sequentially consuming items exactly-once from shared memory, and/or one-or-many threads producing items for consumption. For example, distributing jobs to a worker pool.
Io.Queue suspends your application’s consumer threads when the queue is empty, and automatically resumed when a producer re-populates the queue by adding an item.
Likewise, once the queue is full it suspends producers by blocking/not-resolving requests to add items to the queue. Keep in mind that this blocks producer threads! Blocking producers threads is by design, allowing you to design your application to conserve resources upstream or downstream of the queue.
I made up a lot of stuff because I’ve never actually used Io.Queue before
but I hope it articulates what I mean. I would still have questions after reading that, tbh. Like, does it guarantee serial execution? I kind of assume that it doesn’t because otherwise there wouldn’t be any reason to have multiple consumers, but maybe that’s configurable? There are use cases I can imagine where I might want a queue to be locked by a consumer until it reaches a particular step in its process, at which point it can free the queue for other consumers to take items out of but it will go about doing some further processing before picking up another job 
I guess what I’m getting at is that, yes, arranging the code in the standard library such that its not unnecessarily broad (over-categorization), nor unnecessarily narrow (under-categorization) is important, but it’s also subjective and therefore impossible to perfect, while suffering from diminishing returns on investment. Looking at documentation as a ecosystem and using complementary techniques can help mitigate some of the issues that arise from inevitable tradeoffs.
(
Sorry for writing a wall of text, I’m really into this sort of thing
)