Lost a new commercial user this week :(

Mike Parker via Digitalmars-d digitalmars-d at puremagic.com
Sat Dec 27 00:32:28 PST 2014


On Friday, 26 December 2014 at 16:21:24 UTC, Andrei Alexandrescu 
wrote:
> I thought the std.algorithm stuff is decently documented. What 
> would be the major pain points? -- Andrei

It's fine for someone who is familiar enough with D to decipher 
it. Consider the documentation for sum. The first thing you see 
is the declaration.

auto sum(R)(R r) if (isInputRange!R && !isInfinite!R && 
is(typeof(r.front + r.front)));
auto sum(R, E)(R r, E seed) if (isInputRange!R && !isInfinite!R 
&& is(typeof(seed = seed + r.front)));

I promise you, if you haven't familiarized yourself enough with 
D's templates, template constraints and ranges, this may as well 
be Martian. Then in the description of the function we see this:

If ElementType!R is a floating-point type and R is a 
random-access range with length and slicing, then sum uses the 
pairwise summation algorithm.

Wtf is ElementType? Where is R defined? Searching the site for 
"random-access range" will eventually bear fruit, it doesn't help 
in understanding the whole function.

Then there's a matter of consistency. Where as sum is documented 
with 'R' as a type parameters, others use 'Range'. To the 
hypothetical noob, it's unclear if there is a difference. Little 
things like this add to the frustration level.

The proverbial straw that prompted my blog rant back then was to 
do with std.string. I wanted to split a string on a specific 
character. So I looked in the std.string docs for a split 
function. There wasn't one. There's a 'splitLines' -- I don't 
recall if it existed then, but it wouldn't have been what I was 
looking for anyway. So I searched the docs and found 
std.array.split. I don't recall what the docs looked like then, 
but now this is what we have.

pure @safe S[] split(S)(S s) if (isSomeString!S);

This above is grokkable -- it's fairly clear that S is a string 
and that an array of strings is returned. Then we get these next 
two versions:

auto split(R, E)(R r, E delim) if (isForwardRange!R && 
is(typeof(ElementType!R.init == E.init)));
auto split(alias isTerminator, R)(R r) if (isForwardRange!R && 
is(typeof(unaryFun!isTerminator(r.front))));

Umm... all I want is to split a string on a specific character. 
What's all this mess about ElementTypes and Rs and Es and 
unaryFuns and....

The description, "Eagerly splits s into an array, using delim as 
the delimiter." suggests this is what I'm looking for. I suppose 
I can just pass it a string and a character and see what happens. 
But, that's just trial and errro. The docs don't help me 
understand it. I don't like using functions I don't understand. 
Heaven help me if I find a need for std.array.join:

ElementEncodingType!(ElementType!RoR)[] join(RoR, R)(RoR ror, R 
sep) if (isInputRange!RoR && 
isInputRange!(Unqual!(ElementType!RoR)) && isInputRange!R && 
is(Unqual!(ElementType!(ElementType!RoR)) == 
Unqual!(ElementType!R)));
ElementEncodingType!(ElementType!RoR)[] join(RoR)(RoR ror) if 
(isInputRange!RoR && isInputRange!(Unqual!(ElementType!RoR)));

So the function to split a string on line breaks, which is 
string-specific, is in std.string. The function to split a string 
on whitespace, again string-specific, is in std.array. The 
function to split any range on any element is in std.array. Which 
means I have to think of strings not just as arrays, but as 
ranges, and have to understand that some range functions are in 
std.range, others in std.array and still others in std.algorithm. 
That means that I don't always know where to look when I want to 
do something I've not done before. Even if I do manage to find 
what I'm looking for, I then may discover that it doesn't work 
because I want an array, but the function returns a range and I 
need to convert it to an array, which means arrays aren't really 
ranges like I thought and...

Again, once one is familiar with ranges, template constraints and 
everything that ties all these modules together, the docs are 
very useful. It's the new user experience that sucks. Even for 
those with experience under their belts. I think many programmers 
learn new languages by hacking stuff together and looking through 
the reference documentation as they go. The current state of D's 
documentation is not conducive to that sort of learning. It 
requires a significant investment of time to read up on major D 
features in order to make sense of the docs.

The python docs have been mentioned before and I think it's a 
good example. In addition to the reference, there's a Beginner's 
Guide and a Developer's Guide. We could use that here. It would 
also be extremely beneficial to eliminate the wall of template 
constraints from the function signatures in the reference, be 
consistent with template type parameters (Range,R,S, and so on), 
and make the reference link to relevant sections of the guides. 
For example, it would be great to have every mention of /forward 
range/ or /input range/ and such link to a page on ranges. Or, if 
that's not practical, having a list of links at the top of the 
page.

"std.algorithm makes heavy use of ranges. See link-to-range-page 
in the developer's guide."

It would also be nice to anticipate that people looking to 
operate on strings would look in std.string for things that are 
elsewhere. Once upon a time, the std.string docs actually did 
have a table of links for functions that had been moved to other 
pages. That was convenient and shouldn't have been removed, IMO.

Anything that can be done to minimize the time required to get up 
to speed is going to help. And it has to be self-contained, all 
in the same site. It's easy to answer posts in D.learn by 
pointing people to TDPL, or Ali's book, or even the wiki, but 
it's much more productive for people to be able to easily find 
what they need by following links in the documentation.


More information about the Digitalmars-d mailing list