December 29, 2015
On 12/29/2015 10:20 AM, Adam D. Ruppe wrote:
> On Tuesday, 29 December 2015 at 14:26:48 UTC, Rikki Cattermole wrote:
>> Okay, I remember you saying something a bit different on IRC (at least
>> to my understanding).
>
> Well, I'm still a bit iffy on it, to attach a name I used the first
> member of the enum which might not pass review muster in dmd itself, but
> you could also probably just generate a random name for it.
>
> Actually, I think dmd *does* generate random names for anonymous enums
> internally anyway. I know it does for structs and functions etc.
>
> dmd could probably get away without a name too, since it doesn't care
> about SEO and linking, whereas I do.

Then why document it? If it's for SEO, what SEO scenarios woukd be covered by this feature that can't be done with simple workarounds? -- Andrei

December 30, 2015
On 30/12/15 1:32 PM, Andrei Alexandrescu wrote:
> On 12/29/2015 10:20 AM, Adam D. Ruppe wrote:
>> On Tuesday, 29 December 2015 at 14:26:48 UTC, Rikki Cattermole wrote:
>>> Okay, I remember you saying something a bit different on IRC (at least
>>> to my understanding).
>>
>> Well, I'm still a bit iffy on it, to attach a name I used the first
>> member of the enum which might not pass review muster in dmd itself, but
>> you could also probably just generate a random name for it.
>>
>> Actually, I think dmd *does* generate random names for anonymous enums
>> internally anyway. I know it does for structs and functions etc.
>>
>> dmd could probably get away without a name too, since it doesn't care
>> about SEO and linking, whereas I do.
>
> Then why document it? If it's for SEO, what SEO scenarios woukd be
> covered by this feature that can't be done with simple workarounds? --
> Andrei

The names are for anchors.
E.g. go jump to the comment / enum members.

December 30, 2015
On Wednesday, 30 December 2015 at 00:32:31 UTC, Andrei Alexandrescu wrote:
> Then why document it?

Just on principle, a documentation tool probably shouldn't be limiting the author's ability to document...

This might just be a bug in dmd btw. Looking at the ddoc spec page, it says "documentation comments not associated with a declaration are ignored", but it doesn't say the declaration must be named.

Perhaps dmd ought to be keeping it but isn't.


> If it's for SEO, what SEO scenarios woukd be covered by this feature that can't be done with simple workarounds? -- Andrei

Putting one item per page is far more important than I even realized before getting into this. I was talking to a friend on Sunday night about his early adventures into D. He's managed to convert one of his work scripts that works with Google Docs to D and is working on transitioning a little web form program too.

He consistently found the dlang.org documentation to be undiscoverable and nearly unusable once he did find it. One example he gave as wondering if D had an Array.join function like Javascript.

He searched for "dlang array join" and first, of course, got "did you mean golang?". I like to joke about that being Google's bias, but I betcha it is actually more to do with our poor SEO than any nefarious code on their end.

The top two results he got were:

http://dlang.org/spec/arrays.html

which is no help, it talks about arrays but not the join function

and

http://dlang.org/phobos/std_array.html

which he thought was another false positive because it looked generic again. I told him it *is* the right page... but the wrong section. To actually get to the join function, you need to find it again in the table and hit that second link.


He spent more time than he should have and thought D didn't have an array.join function because the search engine didn't actually return it. It returned two pages that are vaguely related but not specifically what he wanted, and being used to more relevant search requests, wrote off the ddoc as a false positive despite it being the right page!

I asked people in the #d chatroom to repeat this experiment. Nobody even got http://dlang.org/phobos/std_array.html as the top result! Longer time D users did get http://dlang.org/library/std/array/join.html as a top result - good - but nobody actually got the official doc and the ddox only came to those with personalized search that ups the rank score of D related pages.


Contrast that to even the primitive results from my dpldocs.info D-specific search. Look for "array join" and get:


http://dpldocs.info/search/search2?searchTerm=array+join


Whoa, std.array.join is right at the top! And if you click it, you go directly to the relevant function doc.


That's huge.
December 29, 2015
On 12/29/2015 09:09 PM, Adam D. Ruppe wrote:
> Putting one item per page is far more important than I even realized
> before getting into this.

We already have that:

https://dlang.org/library/std/array/join.html

If I search for dlang array join that the third hit on google if I'm logged in, and the SECOND hit if I use an anonymous session that gives google no information about my searching habits. I hope you'll agree that renders the rest of your post moot, for which reason I afforded to snip it.

Adam, there's no nice way to put what follows. You can code a great deal, and I think the world of your engineering skills. But there is something to be said about a bias for action at the expense of strategy. I completely understand it's a lot more fun to start a project than to bring it to completion, but as they say in hardware, it's retired instructions that count. I wish you'd consider converting some of your myriad brilliant snippets into completed projects pushed into the standard distribution for prime time, and also (for this case) to consider strengthening the documentation tools we already have.


Andrei

December 30, 2015
On Wednesday, 30 December 2015 at 04:03:42 UTC, Andrei Alexandrescu wrote:
> On 12/29/2015 09:09 PM, Adam D. Ruppe wrote:
>> Putting one item per page is far more important than I even realized
>> before getting into this.
>
> We already have that:
>
> https://dlang.org/library/std/array/join.html
>
> If I search for dlang array join that the third hit on google if I'm logged in, and the SECOND hit if I use an anonymous session that gives google no information about my searching habits.

Can confirm these search results.
As an aside, the mere formatting of the list of template-constraints on the dlang page made me nope right out of even bothering to figure out how to read them or what the difference between the first and the second overload of join was.
Checking dpldocs for proper formatting and spending half a minute making sense of it I figured that the one was for an exactly matched element type and the other one was to allow joining a baseClass[][] with a subClass[] or something along those lines.

Plus, it's of course really nice that we have these single pages, but for most things you search in google you still get results that lead you to http://dlang.org/phobos/ with pages that usually make your scrollbar pretty tiny and forcing you to either Ctrl+F-guess your way through the page or figuring out what function out of a list of 10-30 functions might possibly suit your need only to scroll back up again and repeat (or look at another module altogether) if it doesn't. Cumbersome and annoying (ie: slow and unproductive).

Also the information that /library even exists is new to me. I have only discovered it through reading this post. So that much for its discoverability (I am new to D, but I did spend probably something like 5-10 hours bugging around phobos documentation by this point and never really knew of /library).

Example searches I did:
http://puu.sh/mdGTt/e71cc7e459.png (only phobos)
http://puu.sh/mdGX8/24250120b1.png (first two results /phobos, third /library)
http://puu.sh/mdH5W/31d3a2432a.png (should be https://dlang.org/library/std/base64/base64_impl.decode.html ideally, but the module overview pages have examples, so this is kind of okay)
http://puu.sh/mdH8g/42a82217e0.png (none of these results mention that you should simply cast(char[]) and then call validate on the casted array, from what I could tell skimming through them for 5 minutes, I might have missed a mention though, which would simply mean it is not obvious enough)

So yeah, we have that, but it should be promoted more, and the documentation still needs lots of love (think the type of formatting and interlinking (even to concepts!) that adams documentation does, and of course the general deal with we need more examples and whatnot).
December 30, 2015
On Wednesday, 30 December 2015 at 14:25:24 UTC, default0 wrote:
> As an aside, the mere formatting of the list of template-constraints on the dlang page made me nope right out of even bothering to figure out how to read them or what the difference between the first and the second overload of join was.

Aye, it is a complete mess and virtually *nobody* bothers looking at them. (BTW, dmd has the same problem in error messages. I plan to format them eventually too, with some kind of highlighting of passed and failing clauses. I already did a proof of concept for ordinary overloading functions and it wasn't actually that hard. I just wish I didn't have other things to do!)

New people are often outright scared away from everything and left with the impression that D is an experts-only language. The Phobos devs know this and have been trying to add more examples - a good, necessary step - but that isn't the whole problem.

When users modify the examples and they fail to compile, they need to understand what's going on. The compiler will complain in terms of those ugly constraints, not in terms of fixed, working examples. They need some way of understanding what it is saying.


Also: I plan to add a doc section called "diagnostics" with sample error messages and translations. I've actually considered doing this before but was stopped by concerns over vertical space.

No kidding, when writing ddoc, I worry about it taking up too much space on the page and will cut content out as a result. If the prototype is compressed, it just leaves a mental bug that says space must matter, use it sparingly.


> Checking dpldocs for proper formatting and spending half a minute making sense of it I figured that the one was for an exactly matched element type and the other one was to allow joining a baseClass[][] with a subClass[] or something along those lines.


The join overloads are basically:

#1: array of arrays joined by an array
   join(["a", "b", "c"], ", "); // the joiner is an array
     -> "a, b, c"

#2: array of arrays joined by an element
   join(["a", "b", "c"], ' '); // the joiner is an element
     -> "a b c"

There is no example for form #2 in the documentation. (BTW I think the examples should be commented too.)

#3: array of arrays joined without anything
   join(["a", "b", "c"])
    -> "abc"


Nothing about inheritance in there, the constraints talk about ElementType!RoR which means (conceptually) it is stripping the "[]" off a type, so for "int[]", it returns "int".


That should probably just be written in the text. (That's another thing people tell me, they come in with a question and I can give them a quick answer, then they ask "why didn't the docs just put it that simply?" And a few times, I go to open a PR but get stalled by the process somewhere....)

But there's a LOT of functions in Phobos so I am trying to automate this because while I can write it for any individual function by hand, writing it for ALL the functions is going to take more time than I have.

> Cumbersome and annoying (ie: slow and unproductive).

absolutely.

> Also the information that /library even exists is new to me. I have only discovered it through reading this post.

Right. New users either don't know about it because it doesn't get linked to much and thus has lower page rank (unless you have already trained Google through D searches to favor D results), or they do find it and are confused as to what version it refers to.

There's been a few people who come to this newsgroup saying "these docs look old, what's up with it?" If they hit the disqus comment, it says "recent activity, 2 years ago" which furthers this impression.

> (none of these results mention that you should simply cast(char[]) and then call validate on the casted array, from what I could tell skimming through them for 5 minutes, I might have missed a mention though, which would simply mean it is not obvious enough)

When you mentioned this before, I went to add it to the docs but couldn't find a good place to put it. The vertical space brain bug hurt me on base64 itself, then the question of linking hurt me when thinking of putting it somewhere else like the wiki, then the question of process killed me when I went to add a new page!

It was actually this experience that tipped me over the edge and I decided to start working on doc infrastructure myself. (I've spent a good amount of time this year trying to fix ddoc itself - starting with the `code` syntax in January - but ddoc itself is only part of the problem)

December 30, 2015
On Wednesday, 30 December 2015 at 15:30:05 UTC, Adam D. Ruppe wrote:
> On Wednesday, 30 December 2015 at 14:25:24 UTC, default0 wrote:
>> Checking dpldocs for proper formatting and spending half a minute making sense of it I figured that the one was for an exactly matched element type and the other one was to allow joining a baseClass[][] with a subClass[] or something along those lines.
>
>
> The join overloads are basically:
>
> #1: array of arrays joined by an array
>    join(["a", "b", "c"], ", "); // the joiner is an array
>      -> "a, b, c"
>
> #2: array of arrays joined by an element
>    join(["a", "b", "c"], ' '); // the joiner is an element
>      -> "a b c"
>
> There is no example for form #2 in the documentation. (BTW I think the examples should be commented too.)
>
> #3: array of arrays joined without anything
>    join(["a", "b", "c"])
>     -> "abc"
>

Yeah, I misinterpreted the "E : <stuff>" to mean "E is or inherits from <stuff>", rechecking the argument deduction rules for templates I think this instead means "E should be deduced as <stuff>".
December 30, 2015
On Wednesday, 30 December 2015 at 15:51:23 UTC, default0 wrote:
> Yeah, I misinterpreted the "E : <stuff>" to mean "E is or inherits from <stuff>", rechecking the argument deduction rules for templates I think this instead means "E should be deduced as <stuff>".

Sort of.. it means "if E can be implicitly converted to <stuff>".

All of this stuff:


RoR ror,
E sep

if (
  isInputRange!RoR &&
  isInputRange!(Unqual!(ElementType!RoR)) &&
  is(E : ElementType!(ElementType!RoR))
)

(doesn't copy paste well, I gotta fix my html a bit)


Could be rewritten as

"ror is an input ranges of input ranges and sep can be implicitly converted to the type of ror's inner range's elements."

Or something like that.



So given: join([[1L], [2L]], 1);


Constraint clause 1: isInputRange!RoR passes because an array, this is long[][] is an input range.

Constraint clause 2: ElementType!RoR is long[] because ElementType basically trips off the outer [] from RoR's type (basically), which is long[][].

Unqual!T trims off qualifiers like const, immutable, etc. Basically it takes the type out of parenthesis. There are none of that here, so long[] is still long[].

Finally, the clause passes because long[] is an input range.


Constraint clause 3: asks if E, which in this example is typeof(1), which is `int`, is implicitly convertible to the type of RoR with *two* layers of [] trimmed off. RoR was long[][] so ElementType!ElementType!(long[][]) returns `long`.

Since `int` implicitly converts to `long` (every int value is a valid long value too), this constraint passes.

If it said is(E == same_stuff), it would fail because int != long. But since it is is(E : stuff), it passes because that allows implicit conversions.



I'll be writing an article with content like this that links from the keyword `if` in those prototypes (Currently it links to dlang.org's spec page but that's not as useful to api doc readers IMO).

I also plan to put a link to this under a "D Concepts" sub-header in the See Also section. Yes, on every page it is used. If someone lands here from a search engine, they shouldn't be assumed to already know everything! And it is hard to search for "dlang function if"...
December 30, 2015
BTW wouldn't it be great if the compiler's error messages showed each level of pass/fail for those constraints? For the docs, I don't mind doing a few special case, hand written things, but the compiler needs something a bit more generic.

I think the way to code that is whenever the compiler is printing an expression that can convert to bool, color it based on the result, and do this through the whole tree from the bottom up.

Then the use could tell at a glance which parts succeeded and failed when reading the error message.

It'd be kinda nice if it showed the result of non-bool things too but that's going to be hard to do on a console without becoming a wall of text, even with whitespace formatting...


But the compiler will come later, for now I gotta do docs!
December 30, 2015
On Wednesday, 30 December 2015 at 16:41:51 UTC, Adam D. Ruppe wrote:
> BTW wouldn't it be great if the compiler's error messages showed each level of pass/fail for those constraints? For the docs, I don't mind doing a few special case, hand written things, but the compiler needs something a bit more generic.
>
> I think the way to code that is whenever the compiler is printing an expression that can convert to bool, color it based on the result, and do this through the whole tree from the bottom up.
>
> Then the use could tell at a glance which parts succeeded and failed when reading the error message.
>
> It'd be kinda nice if it showed the result of non-bool things too but that's going to be hard to do on a console without becoming a wall of text, even with whitespace formatting...
>
>
> But the compiler will come later, for now I gotta do docs!

I was personally thinking that it can't be horribly difficult that given a function signature:

void foo(T)(T arg) if(constraintA!T && constraintB!T || constraintC!T)

That if this cannot be instantiated the compiler prints something like
"Candidate foo(T)(T arg) fails with (true && false || false)"
I sometimes found myself putting static assert(<copy-pasted-segment-of-constraints-with-my-type>, "Result is blabla") and recompiling just to debug these :/