www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - We need better documentation for functions with ranges and templates

reply bachmeier <no spam.com> writes:
It's unanimous, at least among the three of us posting in this 
Reddit thread:

https://www.reddit.com/r/programming/comments/3wqt3p/programming_in_d_ebook_is_at_major_retailers_and/cxyqxuz

Something has to be done with the documentation for Phobos 
functions that involve ranges and templates. The example I gave 
there is

bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2) if 
(isInputRange!Range1 && isInputRange!Range2 && !isInfinite!Range1 
&& !isInfinite!Range2);

Unfortunately, that's less ugly than for a lot of functions. In 
some circumstances, I can see something like that reminding the 
author of the function about some details, but it can only 
confuse anyone else.

There is nothing I can do about this. Who makes these decisions? 
Can we change it to something useful?

Also, I think the documentation for functions involving ranges 
needs more "for dummies" examples. Too many of those functions 
leave the reader not having a clue what to do after calling the 
function. I know how that can be fixed.
Dec 14 2015
next sibling parent reply Jack Stouffer <jack jackstouffer.com> writes:
On Monday, 14 December 2015 at 19:04:46 UTC, bachmeier wrote:
 It's unanimous, at least among the three of us posting in this 
 Reddit thread:

 https://www.reddit.com/r/programming/comments/3wqt3p/programming_in_d_ebook_is_at_major_retailers_and/cxyqxuz

 Something has to be done with the documentation for Phobos 
 functions that involve ranges and templates. The example I gave 
 there is

 bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2) if 
 (isInputRange!Range1 && isInputRange!Range2 && 
 !isInfinite!Range1 && !isInfinite!Range2);

 Unfortunately, that's less ugly than for a lot of functions. In 
 some circumstances, I can see something like that reminding the 
 author of the function about some details, but it can only 
 confuse anyone else.
If you're trying to use Phobos without knowing what template constraints and ranges are, you're going to have a bad time. I'm not sure what else to say here. You can't expect to use the language to it's fullest without understanding these features. It's like trying to use rust with out understanding the borrowing mechanics. And you can't hide the function signature from people because it's necessary for people to know what the constraints for the template arguments are.
 There is nothing I can do about this. Who makes these 
 decisions? Can we change it to something useful?

 Also, I think the documentation for functions involving ranges 
 needs more "for dummies" examples. Too many of those functions 
 leave the reader not having a clue what to do after calling the 
 function. I know how that can be fixed.
I wrote that function, it's documentation, and wrote the examples. In the examples, I clearly show that the function can be used with normal arrays and the explaination in the docs of what the function does is drop dead simple to understand.
Dec 14 2015
next sibling parent reply bachmeier <no spam.com> writes:
On Monday, 14 December 2015 at 19:38:26 UTC, Jack Stouffer wrote:

 If you're trying to use Phobos without knowing what template 
 constraints and ranges are, you're going to have a bad time.
D is doomed if new users have to understand template constraints and ranges to use the standard library. To be honest, I don't know why you should have to understand either of those to test if two arrays have the same length.
 I'm not sure what else to say here. You can't expect to use the 
 language to it's fullest without understanding these features.
There's a difference between using all the features of a language and the documentation of the standard library. The documentation should be accessible to new users of the language.
 I wrote that function, it's documentation, and wrote the 
 examples. In the examples, I clearly show that the function can 
 be used with normal arrays and the explaination in the docs of 
 what the function does is drop dead simple to understand.
I don't think you wrote the part I quoted - as far as I know, it was generated automatically. The parts that you wrote are really good. Other functions should be documented like that. The only criticism I'd have is that there needs to be a link to intro material on ranges.
Dec 14 2015
next sibling parent jmh530 <john.michael.hall gmail.com> writes:
On Monday, 14 December 2015 at 20:25:17 UTC, bachmeier wrote:
 On Monday, 14 December 2015 at 19:38:26 UTC, Jack Stouffer 
 wrote:

 If you're trying to use Phobos without knowing what template 
 constraints and ranges are, you're going to have a bad time.
D is doomed if new users have to understand template constraints and ranges to use the standard library. To be honest, I don't know why you should have to understand either of those to test if two arrays have the same length.
I think you raise valid concerns both with respect to improving the presentation of the documentation and the examples. Function signatures are clearly important for the documentation. It's just a matter of presenting the information so that it is clear to someone new, but also so that an expert can find the information they need easily as well.
Dec 14 2015
prev sibling next sibling parent reply Jack Stouffer <jack jackstouffer.com> writes:
On Monday, 14 December 2015 at 20:25:17 UTC, bachmeier wrote:
 On Monday, 14 December 2015 at 19:38:26 UTC, Jack Stouffer 
 wrote:

 If you're trying to use Phobos without knowing what template 
 constraints and ranges are, you're going to have a bad time.
D is doomed if new users have to understand template constraints and ranges to use the standard library.
C is doomed if you have to understand pointers to use the standard library C++ is doomed if you have to understand templates and iterators to use the STL Rust is doomed if you have to understand borrowing to use the standard library Haskell is doomed if you have to understand functional programming to use the standard library Java is doomed if you have to understand OOP to use the standard library All this is to say that there is a necessary level of overhead to use any language. You can't expect to jump into most languages without learning new concepts and changing the way you look at things. The only languages I know of that doesn't require you to change the way you think are scripting languages and Go, and that's bitting the latter in the ass. Also, most of Phobos doesn't use ranges.
 To be honest, I don't know why you should have to understand 
 either of those to test if two arrays have the same length.
You don't: array1.length == array2.length. isSameLength is designed for comparing input ranges but optimizes down to length checks if either range has a defined length. If you are dealing with strings or arrays you don't need this function at all.
 I'm not sure what else to say here. You can't expect to use 
 the language to it's fullest without understanding these 
 features.
There's a difference between using all the features of a language and the documentation of the standard library. The documentation should be accessible to new users of the language.
I disagree. The Phobos documentation is not a tutorial and shouldn't act like it. If there are concepts that aren't obvious to someone who knows D, for example the fact that you can use lambdas in place of string predicates in a lot of Phobos functions, then fine, document away. But the function signatures require only knowledge that you would gain by reading Ali's book, which is called the official tutorial for a reason.
 The only criticism I'd have is that there needs to be a link to 
 intro material on ranges.
There is, look at the top of this page: http://dlang.org/phobos/std_algorithm.html
Dec 14 2015
next sibling parent reply bachmeier <no spam.com> writes:
On Monday, 14 December 2015 at 20:52:15 UTC, Jack Stouffer wrote:

 You don't: array1.length == array2.length. isSameLength is 
 designed for comparing input ranges but optimizes down to 
 length checks if either range has a defined length. If you are 
 dealing with strings or arrays you don't need this function at 
 all.
All of the examples that *you wrote* for isSameLength are for arrays and strings.
 There's a difference between using all the features of a 
 language and the documentation of the standard library. The 
 documentation should be accessible to new users of the 
 language.
I disagree.
That doesn't make much sense - are those new to the language supposed to learn Phobos by reading the source code? I don't want to debate this. If it's the official position that Phobos documentation is written for experienced users of the language, then so be it. I'll have to tell others to use a practical language.
Dec 14 2015
next sibling parent Jack Stouffer <jack jackstouffer.com> writes:
On Monday, 14 December 2015 at 22:31:33 UTC, bachmeier wrote:
 On Monday, 14 December 2015 at 20:52:15 UTC, Jack Stouffer 
 wrote:
 You don't: array1.length == array2.length. isSameLength is 
 designed for comparing input ranges but optimizes down to 
 length checks if either range has a defined length. If you are 
 dealing with strings or arrays you don't need this function at 
 all.
All of the examples that *you wrote* for isSameLength are for arrays and strings.
Yes, they are, because strings and arrays are the most simple input ranges. But the fact that you didn't know that arrays have a length parameter tells me you tried using the language raw and you got confused. I don't know why it's surprising to you that trying to use a systems language without reading any tutorials is going to end up with you hitting walls when the inevitable complexity rears its head.
 I disagree.
That doesn't make much sense - are those new to the language supposed to learn Phobos by reading the source code?
No you're supposed to learn it by reading the official tutorial that is linked on every single page in dlang.org in the sidebar.
 I don't want to debate this.
Then why create the thread in the first place? Did you really expect everyone to just accept your idea at face value and there wouldn't be no discussion at all?
 If it's the official position that Phobos documentation is 
 written for experienced users of the language, then so be it. 
 I'll have to tell others to use a practical language.
It's not the official position. I'm just a contributor and have no power what so ever.
Dec 14 2015
prev sibling parent anonymous <anonymous example.com> writes:
On 14.12.2015 23:31, bachmeier wrote:
 I don't want to debate this. If it's the official position that Phobos
 documentation is written for experienced users of the language, then so
 be it. I'll have to tell others to use a practical language.
Relax, Jack Stouffer is not the spokesman for D or phobos. He doesn't express official positions. (Not implying that you tried to give the impression, Jack.) As far as I see, people generally agree with you that the current way of displaying the signatures is too cryptic. What to do exactly about it is open for debate, of course. And then someone actually has to do the work, of course.
Dec 14 2015
prev sibling parent Chris Wright <dhasenan gmail.com> writes:
On Mon, 14 Dec 2015 20:52:15 +0000, Jack Stouffer wrote:
 C++ is doomed if you have to understand templates and iterators 
 to use the STL
C++ existed long before the STL. But a putative C++ clone that had sorely lacking documentation about iterators and put them everywhere in its standard library would struggle more than it would otherwise. It would be worse if what documentation existed were cluttered with dense syntax that novices agree is confusing. And doom would be assured if the standard library authors were dismissive of the needs of programmers who are not as familiar with the language as the core development team.
 Also, most of Phobos doesn't use ranges.
Quick survey by module: std.algorithm: 6/6 modules. std.array: yes. std.ascii: no. std.base64: yes. std.bigint: no. std.bitmanip: yes. std.compiler: no. std.complex: no. std.concurrency: no. std.container: 5/6 modules. std.conv: yes. std.csv: yes. std.datetime: yes. std.demangle: no. At this point I got bored, but suffice it to say, a *lot* of Phobos uses ranges. And a lot more will. Ranges are central to modern D and to making composable functions. Plus a lot of the stuff that does use ranges is pretty important and widely used and useful. It's the sort of thing that new programmers are pointed to and told "You should be using this." Finally, requests for better documentation or to bear in mind people who have not been living and breathing D for months should not be controversial.
Dec 14 2015
prev sibling parent Joakim <dlang joakim.fea.st> writes:
On Monday, 14 December 2015 at 20:25:17 UTC, bachmeier wrote:
 On Monday, 14 December 2015 at 19:38:26 UTC, Jack Stouffer 
 wrote:

 If you're trying to use Phobos without knowing what template 
 constraints and ranges are, you're going to have a bad time.
D is doomed if new users have to understand template constraints and ranges to use the standard library. To be honest, I don't know why you should have to understand either of those to test if two arrays have the same length.
I agree. I was just debugging one of the phobos tests on Android/ARM and I couldn't make head nor tails of what the function was supposed to do, after a couple minutes' skim: http://dlang.org/phobos/std_algorithm_sorting.html#nextEvenPermutation That may be an obscure function that requires technical knowledge to use, but any function should first have a layman's description, in case the layman might want to use it. Template constraints and ranges in the Phobos docs definitely suffer from this. Saying that users should always read the relevant sections of Ali's book first is not going to work, as most users don't RTFM. The problem is that documentation for an OSS project, particularly breaking it down for someone new to the language, is a classic tragedy of the commons: work that nobody benefits personally from and isn't very interesting to do, so I understand why it's the way it is. I wonder if a possible solution is to automatically generate some doc comments and links to glossary/tutorials from the template constraints, in addition to the formatting changes others have suggested.
Dec 14 2015
prev sibling next sibling parent reply Meta <jared771 gmail.com> writes:
On Monday, 14 December 2015 at 19:38:26 UTC, Jack Stouffer wrote:
 If you're trying to use Phobos without knowing what template 
 constraints and ranges are, you're going to have a bad time.

 I'm not sure what else to say here.
No, stuff like the following is indefensible. The current documentation is nearly opaque to newcomers and *needs* to be fixed. bool isPermutation(AllocateGC allocate_gc, Range1, Range2)(Range1 r1, Range2 r2) if (allocate_gc == AllocateGC.yes && isForwardRange!Range1 && isForwardRange!Range2 && !isInfinite!Range1 && !isInfinite!Range2); Compare that with the DDOX output, which is at least a little bit more readable (but also leaves a lot of room for improvement). bool isPermutation(std.typecons.Flag!("allocateGC").Flag allocate_gc, Range1, Range2)( Range1 r1, Range2 r2 ) if (allocate_gc == AllocateGC.yes && isForwardRange!Range1 && isForwardRange!Range2 && !isInfinite!Range1 && !isInfinite!Range2);
Dec 14 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
One thing we definitely need to do is make the template 
constraints rendered better in documentation, and also allow user 
content in them. We've discussed this several times but no clear 
path emerged so far. Maybe a strong champion would come forward?

I'm thinking along the lines of:

* Change ddoc to output the constraint separately under a 
DDOC_CONSTRAINT macro.

* Allow ddoc comments inside macros:

bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2)
if (isInputRange!Range1 && isInputRange!Range2 && 
!isInfinite!Range1 && !isInfinite!Range2
/**
`Range1` and `Range2` must be both non-infinite input ranges.
*/
);

then format that comment as a DDOC_CONSTRAINT_USERTEXT or 
something.

These would be good steps to take.


Andrei
Dec 14 2015
next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 12/14/2015 12:53 PM, Andrei Alexandrescu wrote:

 I'm thinking along the lines of:

 * Change ddoc to output the constraint separately under a
 DDOC_CONSTRAINT macro.

 * Allow ddoc comments inside macros:

 bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2)
 if (isInputRange!Range1 && isInputRange!Range2 && !isInfinite!Range1 &&
 !isInfinite!Range2
 /**
 `Range1` and `Range2` must be both non-infinite input ranges.
 */
 );
Can we simplify it even more? Just this much: bool isSameLength(Range1 r1, Range2 r2) Then some text that follows: Range1 is a template parameter: default value: blah Range2 is a template parameter Template constraints: if (isInputRange!Range1 && isInputRange!Range2 && !isInfinite!Range1 && !isInfinite!Range2) There can be a hover-over or a click to see the full signature. Ali
Dec 14 2015
parent Adam D. Ruppe <destructionator gmail.com> writes:
On Monday, 14 December 2015 at 21:02:05 UTC, Ali Çehreli wrote:
 bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2)
 if (isInputRange!Range1 && isInputRange!Range2 &&
!isInfinite!Range1 &&
 !isInfinite!Range2
Can we simplify it even more? Just this much:
You know, I think it is a lot more readable already just putting in some whitespace. bool isSameLength (Range1, Range2) (Range1 r1, Range2 r2) if( isInputRange!Range1 && isInputRange!Range2 && !isInfinite!Range1 && !isInfinite!Range2 ) --------------------------------------- Maybe we could run the outputted code through a D source formatter?! Heck, the compiler error messages might be easier to read if it formatted with liberal whitespace too, though there is the tiny concern there that other tools might expect one error per line... but i say meh to that, we already break that rule.
Dec 14 2015
prev sibling next sibling parent reply Meta <jared771 gmail.com> writes:
On Monday, 14 December 2015 at 20:53:53 UTC, Andrei Alexandrescu 
wrote:
 One thing we definitely need to do is make the template 
 constraints rendered better in documentation, and also allow 
 user content in them. We've discussed this several times but no 
 clear path emerged so far. Maybe a strong champion would come 
 forward?

 I'm thinking along the lines of:

 * Change ddoc to output the constraint separately under a 
 DDOC_CONSTRAINT macro.

 * Allow ddoc comments inside macros:

 bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2)
 if (isInputRange!Range1 && isInputRange!Range2 && 
 !isInfinite!Range1 && !isInfinite!Range2
 /**
 `Range1` and `Range2` must be both non-infinite input ranges.
 */
 );

 then format that comment as a DDOC_CONSTRAINT_USERTEXT or 
 something.

 These would be good steps to take.


 Andrei
I'm not particularly familiar with DDOC. Is there some documentation on creating new macros?
Dec 14 2015
parent Adam D. Ruppe <destructionator gmail.com> writes:
On Monday, 14 December 2015 at 21:02:10 UTC, Meta wrote:
 I'm not particularly familiar with DDOC. Is there some 
 documentation on creating new macros?
This text is output by the compiler, so it would be a matter of making the compiler output it with more information. It used to be called doc.c.... I'm sure it is doc.d now, the code is fairly simple and just builds strings from the code objects.
Dec 14 2015
prev sibling next sibling parent reply "H. S. Teoh via Digitalmars-d" <digitalmars-d puremagic.com> writes:
On Mon, Dec 14, 2015 at 08:53:53PM +0000, Andrei Alexandrescu via Digitalmars-d
wrote:
 One thing we definitely need to do is make the template constraints
 rendered better in documentation, and also allow user content in them.
 We've discussed this several times but no clear path emerged so far.
 Maybe a strong champion would come forward?
 
 I'm thinking along the lines of:
[...] This has already been filed since a long time ago: https://issues.dlang.org/show_bug.cgi?id=13676 It just needs somebody to actually implement it. AFAICT it shouldn't be too hard, as ddoc.d already has most of the necessary machinery for it. T -- First Rule of History: History doesn't repeat itself -- historians merely repeat each other.
Dec 14 2015
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/14/15 4:11 PM, H. S. Teoh via Digitalmars-d wrote:
 On Mon, Dec 14, 2015 at 08:53:53PM +0000, Andrei Alexandrescu via
Digitalmars-d wrote:
 One thing we definitely need to do is make the template constraints
 rendered better in documentation, and also allow user content in them.
 We've discussed this several times but no clear path emerged so far.
 Maybe a strong champion would come forward?

 I'm thinking along the lines of:
[...] This has already been filed since a long time ago: https://issues.dlang.org/show_bug.cgi?id=13676 It just needs somebody to actually implement it. AFAICT it shouldn't be too hard, as ddoc.d already has most of the necessary machinery for it.
I preapproved the issue. -- Andrei
Dec 14 2015
prev sibling parent Chris Wright <dhasenan gmail.com> writes:
On Mon, 14 Dec 2015 20:53:53 +0000, Andrei Alexandrescu wrote:

 One thing we definitely need to do is make the template constraints
 rendered better in documentation, and also allow user content in them.
 We've discussed this several times but no clear path emerged so far.
 Maybe a strong champion would come forward?
 
 I'm thinking along the lines of:
 
 * Change ddoc to output the constraint separately under a
 DDOC_CONSTRAINT macro.
 
 * Allow ddoc comments inside macros:
 
 bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2)
 if (isInputRange!Range1 && isInputRange!Range2 && !isInfinite!Range1 &&
 !isInfinite!Range2 /**
 `Range1` and `Range2` must be both non-infinite input ranges.
 */
 );
 
 then format that comment as a DDOC_CONSTRAINT_USERTEXT or something.
 
 These would be good steps to take.
 
 
 Andrei
From your lips to God's ears.
Dec 14 2015
prev sibling next sibling parent carljv <carljv gmail.com> writes:
I think it's really just a design issue--I agree that you can't 
ignore information about ranges and constraints altogether. But 
the documentation doesn't reflect any hierarchy of the importance 
of information. In the example:

 bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2) if 
 (isInputRange!Range1 && isInputRange!Range2 && 
 !isInfinite!Range1 && !isInfinite!Range2);
The most important thing to know is that it accepts two ranges and outputs a bool. The template constraints are secondary (and for the most part obvious), but they're in the same visual hierarchy (line, font size, weight, etc.) as the basic signature. So it's just extremely noisy. I think even just putting template constraints in a subordinate section of the documentation would help a lot. Beginners can just look at the signature and be good to go 99% of the time; others can look under the hood easily. The other noisy aspect is the type repetition of Range1 and Range2. I don't know what to do about that---maybe a terser convention for range type params would help. (Typically type parameters are single letters for this reason in many languages.) I notice some functions use R1 and R2 instead of Range1 and Range2. On Monday, 14 December 2015 at 19:38:26 UTC, Jack Stouffer wrote:
 On Monday, 14 December 2015 at 19:04:46 UTC, bachmeier wrote:
 It's unanimous, at least among the three of us posting in this 
 Reddit thread:

 https://www.reddit.com/r/programming/comments/3wqt3p/programming_in_d_ebook_is_at_major_retailers_and/cxyqxuz

 Something has to be done with the documentation for Phobos 
 functions that involve ranges and templates. The example I 
 gave there is

 bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2) if 
 (isInputRange!Range1 && isInputRange!Range2 && 
 !isInfinite!Range1 && !isInfinite!Range2);

 Unfortunately, that's less ugly than for a lot of functions. 
 In some circumstances, I can see something like that reminding 
 the author of the function about some details, but it can only 
 confuse anyone else.
If you're trying to use Phobos without knowing what template constraints and ranges are, you're going to have a bad time. I'm not sure what else to say here. You can't expect to use the language to it's fullest without understanding these features. It's like trying to use rust with out understanding the borrowing mechanics. And you can't hide the function signature from people because it's necessary for people to know what the constraints for the template arguments are.
 There is nothing I can do about this. Who makes these 
 decisions? Can we change it to something useful?

 Also, I think the documentation for functions involving ranges 
 needs more "for dummies" examples. Too many of those functions 
 leave the reader not having a clue what to do after calling 
 the function. I know how that can be fixed.
I wrote that function, it's documentation, and wrote the examples. In the examples, I clearly show that the function can be used with normal arrays and the explaination in the docs of what the function does is drop dead simple to understand.
Dec 14 2015
prev sibling parent Chris Wright <dhasenan gmail.com> writes:
On Mon, 14 Dec 2015 19:38:26 +0000, Jack Stouffer wrote:
 If you're trying to use Phobos without knowing what template constraints
 and ranges are, you're going to have a bad time.
I completely agree about ranges. On that note, it would be nice if std.range actually told you what interface a range has to honor. It points you to Andrei's article, but that uses C++. It would also be awesome if std.algorithm reminded you of that interface right there in the package documentation, seeing as it makes such extensive use of ranges. It does better than std.range by linking to Ali's book, but Ali introduces things to you rather slowly. Yes, std.range.primitives defines isInputRange and friends. However, it's not defining ranges in general, just a collection of specific types of ranges. It's not telling you that foreach works with ranges. And it's using odd terminology -- the module is called "primitives" when it really defines the interface that a range must adhere to (and provides a random smattering of convenience methods that don't seem to belong), and it calls the methods and properties that a range must define "primitives" for maximum confusion. So for ranges. Template constraints, on the other hand? Not so much. You can ignore them and hope that your stuff works and get confused when it doesn't. Or you can glance at a method's signature and see that it's two or three lines long and get scared. And when you decide, a few weeks or months into using D, to use templates, you'll quickly discover it's far less work not to use constraints and you get much better error messages.
 I'm not sure what else to say here. You can't expect to use the language
 to it's fullest without understanding these features.
Right, but std.algorithm is full of stuff that novices need to use early on. They're not trying to use the language to its fullest; they're just trying to use the basic parts of the standard library. There's also the problem that the template constraint is made so prominent when the examples are far more useful for most people.
Dec 14 2015
prev sibling next sibling parent reply "H. S. Teoh via Digitalmars-d" <digitalmars-d puremagic.com> writes:
On Mon, Dec 14, 2015 at 07:04:46PM +0000, bachmeier via Digitalmars-d wrote:
 It's unanimous, at least among the three of us posting in this Reddit
 thread:
 
 https://www.reddit.com/r/programming/comments/3wqt3p/programming_in_d_ebook_is_at_major_retailers_and/cxyqxuz
 
 Something has to be done with the documentation for Phobos functions
 that involve ranges and templates. The example I gave there is
 
 bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2) if
 (isInputRange!Range1 && isInputRange!Range2 && !isInfinite!Range1 &&
 !isInfinite!Range2);
 
 Unfortunately, that's less ugly than for a lot of functions. In some
 circumstances, I can see something like that reminding the author of
 the function about some details, but it can only confuse anyone else.
https://issues.dlang.org/show_bug.cgi?id=13676
 There is nothing I can do about this. Who makes these decisions? Can
 we change it to something useful?
What would constitute "useful" to you?
 Also, I think the documentation for functions involving ranges needs
 more "for dummies" examples. Too many of those functions leave the
 reader not having a clue what to do after calling the function. I know
 how that can be fixed.
Let's see the PR's, then. T -- The computer is only a tool. Unfortunately, so is the user. -- Armaphine, K5
Dec 14 2015
parent bachmeier <no spam.com> writes:
On Monday, 14 December 2015 at 19:50:47 UTC, H. S. Teoh wrote:

 There is nothing I can do about this. Who makes these 
 decisions? Can we change it to something useful?
What would constitute "useful" to you?
Removing what is there and leaving it blank would be better. At least new D programmers wouldn't run away.
 Also, I think the documentation for functions involving ranges 
 needs more "for dummies" examples. Too many of those functions 
 leave the reader not having a clue what to do after calling 
 the function. I know how that can be fixed.
Let's see the PR's, then.
You have and you will, as it fits my schedule. Hopefully I'm not the only one or it will take a long time.
Dec 14 2015
prev sibling next sibling parent reply dnewbie <d d.com> writes:
On Monday, 14 December 2015 at 19:04:46 UTC, bachmeier wrote:
 It's unanimous, at least among the three of us posting in this 
 Reddit thread:
 ...
Take for example C# Docs: https://msdn.microsoft.com/en-us/library/system.collections.arraylist.addrange.aspx Syntax C#: public virtual void AddRange( ICollection c ) Parameters: c Type: System.Collections.ICollection The ICollection whose elements should be added to the end of the ArrayList. The collection itself cannot be null, but it can contain elements that are null. Clean, simple and instructive! On the otherhand, imagine a newbie looking: bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2) if (isInputRange!Range1 && isInputRange!Range2 && !isInfinite!Range1 && !isInfinite!Range2); Well, most of my friends of college that I indicated D language thinks the D docs is confusing. Ron.
Dec 14 2015
next sibling parent reply Jack Stouffer <jack jackstouffer.com> writes:
On Monday, 14 December 2015 at 19:56:29 UTC, dnewbie wrote:
 On Monday, 14 December 2015 at 19:04:46 UTC, bachmeier wrote:
 It's unanimous, at least among the three of us posting in this 
 Reddit thread:
 ...
Take for example C# Docs: https://msdn.microsoft.com/en-us/library/system.collections.arraylist.addrange.aspx Syntax C#: public virtual void AddRange( ICollection c ) Parameters: c Type: System.Collections.ICollection The ICollection whose elements should be added to the end of the ArrayList. The collection itself cannot be null, but it can contain elements that are null. Clean, simple and instructive!
You're not really comparing apples to apples here. isSameLength uses generics and type constraints while AddRange uses OOP. isSameLength will accept any type that conforms to the concept of a finite input range while AddRange will only accept values that inherit from or are System.Collections.ICollection. One is inherently more complex than the other.
 On the otherhand, imagine a newbie looking:

 bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2) if 
 (isInputRange!Range1 && isInputRange!Range2 && 
 !isInfinite!Range1 && !isInfinite!Range2);
They can look at the examples below and see that the function accepts strings and arrays. And they can look at the parameters section and see that r1 and r2 need to be "finite input range"s if they can't read the function signature.
Dec 14 2015
next sibling parent reply "H. S. Teoh via Digitalmars-d" <digitalmars-d puremagic.com> writes:
On Mon, Dec 14, 2015 at 08:08:20PM +0000, Jack Stouffer via Digitalmars-d wrote:
 On Monday, 14 December 2015 at 19:56:29 UTC, dnewbie wrote:
[...]
On the otherhand, imagine a newbie looking:

bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2) if
(isInputRange!Range1 && isInputRange!Range2 && !isInfinite!Range1 &&
!isInfinite!Range2);
They can look at the examples below and see that the function accepts strings and arrays. And they can look at the parameters section and see that r1 and r2 need to be "finite input range"s if they can't read the function signature.
While I agree with you in principle, I also think that one has to admit, that function signature looks far more scary than it actually is. A lot of this can probably be attributed to lack of control over the formatting of various elements in the signature. It's just a single dense blob of stuff that you have to stare at for at least 2 full seconds before you can parse it completely (or longer if you're new to D). Imagine, for example, if the docs were to be formatted a little better, say something like this: bool isSameLength(Range1, Range2) (Range1 r1, Range2 r2) if (isInputRange!Range1 && isInputRange!Range2 && !isInfinite!Range1 && !isInfinite!Range2) The sig constraint block can be rendered in a different font / font size / color / whatever. The CT parameters similarly can be visually distinguished from the RT parameters. Currently, this isn't possible yet, due to limitations in ddoc: https://issues.dlang.org/show_bug.cgi?id=13676 In theory, though, this should not be hard to add -- somebody just has to take the time to implement it in ddoc.d. Once we have that, it's just a matter of putting in the right macros in the ddoc stylesheets. T -- Computerese Irregular Verb Conjugation: I have preferences. You have biases. He/She has prejudices. -- Gene Wirchenko
Dec 14 2015
parent =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Monday, 14 December 2015 at 20:16:25 UTC, H. S. Teoh wrote:
 Imagine, for example, if the docs were to be formatted a little 
 better, say something like this:

 	bool isSameLength(Range1, Range2)
 	                 (Range1 r1, Range2 r2)
 		if (isInputRange!Range1 &&
 		    isInputRange!Range2 &&
 		    !isInfinite!Range1 &&
 		    !isInfinite!Range2)

 The sig constraint block can be rendered in a different font / 
 font size / color / whatever. The CT parameters similarly can 
 be visually distinguished from the RT parameters.
That would be a great improvement.
Dec 17 2015
prev sibling parent dnewbie <d d.com> writes:
On Monday, 14 December 2015 at 20:08:20 UTC, Jack Stouffer wrote:
 You're not really comparing apples to apples here
In fact I'm not, but the main focus here was about the simplicity of the layout used on the C# doc. You can see others examples there easily including templates and generics interface.
 On the otherhand, imagine a newbie looking:

 bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2) if 
 (isInputRange!Range1 && isInputRange!Range2 && 
 !isInfinite!Range1 && !isInfinite!Range2);
They can look at the examples below and see that the function accepts strings and arrays. And they can look at the parameters section and see that r1 and r2 need to be "finite input range"s if they can't read the function signature.
Yes they can and this isn't hard to understand, but remember there are newcomers every day. I think it should be simpler like MSDN does: Syntax: bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2) Parameters: Type r1, r2 : Input range. Both r1, r2 : needs to be finite. I think it's better than currently. But this is my thoughts over the problems that my friends encounter with D's docs. Ron.
Dec 14 2015
prev sibling parent reply ZombineDev <valid_email he.re> writes:
On Monday, 14 December 2015 at 19:56:29 UTC, dnewbie wrote:
 On Monday, 14 December 2015 at 19:04:46 UTC, bachmeier wrote:
 It's unanimous, at least among the three of us posting in this 
 Reddit thread:
 ...
Take for example C# Docs: https://msdn.microsoft.com/en-us/library/system.collections.arraylist.addrange.aspx Syntax C#: public virtual void AddRange( ICollection c ) Parameters: c Type: System.Collections.ICollection The ICollection whose elements should be added to the end of the ArrayList. The collection itself cannot be null, but it can contain elements that are null. Clean, simple and instructive!
You are really comparing apples to oranges. You should look at signatures of the LINQ functions: https://msdn.microsoft.com/en-us/library/bb535047(v=vs.100).aspx https://msdn.microsoft.com/en-us/library/bb534732(v=vs.100).aspx https://msdn.microsoft.com/en-us/library/hh229621(v=vs.103).aspx https://msdn.microsoft.com/en-us/library/hh229412(v=vs.103).aspx https://msdn.microsoft.com/en-us/library/hh211747(v=vs.103).aspx https://msdn.microsoft.com/en-us/library/hh211886(v=vs.103).aspx https://msdn.microsoft.com/en-us/library/hh229310(v=vs.103).aspx https://msdn.microsoft.com/en-us/library/hh229364(v=vs.103).aspx https://msdn.microsoft.com/en-us/library/hh229473(v=vs.103).aspx https://msdn.microsoft.com/en-us/library/hh212066(v=vs.103).aspx https://msdn.microsoft.com/en-us/library/hh244290(v=vs.103).aspx https://msdn.microsoft.com/en-us/library/hh229392(v=vs.103).aspx https://msdn.microsoft.com/en-us/library/hh229708(v=vs.103).aspx https://msdn.microsoft.com/en-us/library/hh229926(v=vs.103).aspx https://msdn.microsoft.com/en-us/library/hh229008(v=vs.103).aspx https://msdn.microsoft.com/en-us/library/hh229778(v=vs.103).aspx https://msdn.microsoft.com/en-us/library/hh229729(v=vs.103).aspx And then you have one of the most used methods - .Count: https://msdn.microsoft.com/en-us/library/bb338038(v=vs.100).aspx Where presumably, for the sake of simplicity, the docs don't even bother to mention that it is almost always O(n), because non of the Enumerable extention methods preserve the underlying ICollection interace.
Dec 15 2015
next sibling parent ZombineDev <valid_email he.re> writes:
On Tuesday, 15 December 2015 at 09:57:00 UTC, ZombineDev wrote:
 And then you have one of the most used methods - .Count:
 https://msdn.microsoft.com/en-us/library/bb338038(v=vs.100).aspx

 Where presumably, for the sake of simplicity, the docs don't 
 even bother to mention that it is almost always O(n), because 
 non of the Enumerable extention methods preserve the underlying 
 ICollection interace.
I honestly think that the documentation of walkLength in Phobos is much better, though an example would be nice: https://dlang.org/phobos/std_range_primitives.html#.walkLength
Dec 15 2015
prev sibling next sibling parent reply rumbu <rumbu rumbu.ro> writes:
On Tuesday, 15 December 2015 at 09:57:00 UTC, ZombineDev wrote:

 And then you have one of the most used methods - .Count:
 https://msdn.microsoft.com/en-us/library/bb338038(v=vs.100).aspx

 Where presumably, for the sake of simplicity, the docs don't 
 even bother to mention that it is almost always O(n), because 
 non of the Enumerable extention methods preserve the underlying 
 ICollection interace.
Looking at the .net source code, the Count extension method is also doing a best effort "count" by querying the ICollection interface. public static int Count<TSource>(this IEnumerable<TSource> source) { if (source == null) throw Error.ArgumentNull("source"); ICollection<TSource> collection1 = source as ICollection<TSource>; if (collection1 != null) return collection1.Count; ICollection collection2 = source as ICollection; if (collection2 != null) return collection2.Count; int num = 0; using (IEnumerator<TSource> enumerator = source.GetEnumerator()) { while (enumerator.MoveNext()) checked { ++num; } } return num; } The Remarks section clearly states the same thing: "If the type of source implements ICollection<T>, that implementation is used to obtain the count of elements. Otherwise, this method determines the count." And personally, I found the MS remark more compact and more user friendly than: "This is a best-effort implementation of length for any kind of range. If hasLength!Range, simply returns range.length without checking upTo (when specified). Otherwise, walks the range through its length and returns the number of elements seen. Performes Ο(n) evaluations of range.empty and range.popFront(), where n is the effective length of range." Not everybody is licensed in computational complexity theory to understand what O(n) means.
Dec 15 2015
next sibling parent reply ZombineDev <valid_email he.re> writes:
On Tuesday, 15 December 2015 at 11:26:04 UTC, rumbu wrote:
 Looking at the .net source code, the Count extension method is 
 also doing a best effort "count" by querying the ICollection 
 interface.
Yes, I have looked at the source code, before writing this, so I knew exactly how it worked. In short : terrible, because it relies only on OOP. But that's not the point. Why should anyone need to look at the source code, to see what this function does? I thought this is what the docs were supposed to tell.
 public static int Count<TSource>(this IEnumerable<TSource> [...]

 The Remarks section clearly states the same thing:

 "If the type of source implements ICollection<T>, that 
 implementation is used to obtain the count of elements. 
 Otherwise, this method determines the count."


 And personally, I found the MS remark more compact and more 
 user friendly than:
 [...]
If you look at table at the beginning of page (https://dlang.org/phobos/std_range_primitives.html) you can clearly see a nice concise description of the function. Even if you don't know complexity theory there's the word "Compute" which should give you an idea that the function performs some non-trivial amount of work. Unlike:
 Returns the number of elements in a sequence.
Which implies that it only returns a number - almost like an ordinary getter property. I am scared to think that if back then C# got extension properties, it might have been implemented as such.
 Not everybody is licensed in computational complexity theory to 
 understand what O(n) means.
LOL. Personally, I would never want to use any software written by a programmer, who can't tell the difference. Well ok, let's consider a novice programmer who hasn't studied yet complexity theory. Option A: They look at the documentation and see there's some strange O(n) thing that they don't know. They look it up in google and find the wonderful world of complexity theory. They become more educated and are grateful the people who wrote the documentation for describing more accurately the requirements of the function. That way they can easily decide how using such function would impact the performance of their system. Option B: They look at the documentation and see that there's some strange O(n) thing that they don't know. They decide that it's extremely inhumane for the docs to expect such significant knowledge from the reader and they decide to quit. Such novices that do not want to learn are better off choosing a different profession, than inflicting their poor written software on the world.
Dec 15 2015
next sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Tuesday, 15 December 2015 at 12:28:02 UTC, ZombineDev wrote:
 Not everybody is licensed in computational complexity theory 
 to understand what O(n) means.
LOL. Personally, I would never want to use any software written by a programmer, who can't tell the difference. Well ok, let's consider a novice programmer who hasn't studied yet complexity theory.
Most experienced programmers have a _very_ poor understanding of complexity theory, the associated notation and applicability. A little bit of sloppy O(1), O(log N) and O(N), is ok, but for anything more than that it becomes more confusing than useful. E.g. the effects are not necessarily measurable for your program. You need more accurate descriptions to understand the effects than O(N^2).
Dec 15 2015
parent ZombineDev <valid_email he.re> writes:
On Tuesday, 15 December 2015 at 13:47:20 UTC, Ola Fosheim Grøstad 
wrote:
 On Tuesday, 15 December 2015 at 12:28:02 UTC, ZombineDev wrote:
 Not everybody is licensed in computational complexity theory 
 to understand what O(n) means.
LOL. Personally, I would never want to use any software written by a programmer, who can't tell the difference. Well ok, let's consider a novice programmer who hasn't studied yet complexity theory.
Most experienced programmers have a _very_ poor understanding of complexity theory, the associated notation and applicability. A little bit of sloppy O(1), O(log N) and O(N), is ok, but for anything more than that it becomes more confusing than useful. E.g. the effects are not necessarily measurable for your program. You need more accurate descriptions to understand the effects than O(N^2).
I never said that you need to be an expert, but at least you should be able to tell the difference between O(n) and O(1) like in this particular case. This is very basic stuff.
Dec 15 2015
prev sibling parent reply rumbu <rumbu rumbu.ro> writes:
On Tuesday, 15 December 2015 at 12:28:02 UTC, ZombineDev wrote:
 On Tuesday, 15 December 2015 at 11:26:04 UTC, rumbu wrote:
 Looking at the .net source code, the Count extension method is 
 also doing a best effort "count" by querying the ICollection 
 interface.
Yes, I have looked at the source code, before writing this, so I knew exactly how it worked. In short : terrible, because it relies only on OOP. But that's not the point. Why should anyone need to look at the source code, to see what this function does? I thought this is what the docs were supposed to tell.
 public static int Count<TSource>(this IEnumerable<TSource> 
 [...]

 The Remarks section clearly states the same thing:

 "If the type of source implements ICollection<T>, that 
 implementation is used to obtain the count of elements. 
 Otherwise, this method determines the count."


 And personally, I found the MS remark more compact and more 
 user friendly than:
 [...]
If you look at table at the beginning of page (https://dlang.org/phobos/std_range_primitives.html) you can clearly see a nice concise description of the function. Even if you don't know complexity theory there's the word "Compute" which should give you an idea that the function performs some non-trivial amount of work. Unlike:
 Returns the number of elements in a sequence.
Which implies that it only returns a number - almost like an ordinary getter property. I am scared to think that if back then C# got extension properties, it might have been implemented as such.
 Not everybody is licensed in computational complexity theory 
 to understand what O(n) means.
LOL. Personally, I would never want to use any software written by a programmer, who can't tell the difference. Well ok, let's consider a novice programmer who hasn't studied yet complexity theory. Option A: They look at the documentation and see there's some strange O(n) thing that they don't know. They look it up in google and find the wonderful world of complexity theory. They become more educated and are grateful the people who wrote the documentation for describing more accurately the requirements of the function. That way they can easily decide how using such function would impact the performance of their system. Option B: They look at the documentation and see that there's some strange O(n) thing that they don't know. They decide that it's extremely inhumane for the docs to expect such significant knowledge from the reader and they decide to quit. Such novices that do not want to learn are better off choosing a different profession, than inflicting their poor written software on the world.
We are talking about a better documentation, not about the C# vs D performance, we already know the winner. Since C# is an OOP-only language, there is only one way to do reflection - using OOP, (voluntarily ignoring the fact that NGen will reduce this call to a simple memory read in case of arrays). Your affirmation:
 the docs don't even bother to mention that it is almost always 
 O(n), because non of the > Enumerable extention methods 
 preserve the underlying ICollection interace
was false and you don't need to look to the source code to find out, the Remarks section is self-explanatory: "If the type of source implements ICollection<T>, that implementation is used to obtain the count of elements. Otherwise, this method determines the count." This is a *good* documentation: - "Count" is a better name than "walkLength"; every other programming language will use concepts similar to count, cnt, length, len. - You don't need to understand computer science terms to find out what a function does; - If you are really interested about more than finding out the number of elements, there is a performance hint in the Remarks section. - Links are provided to concepts: even the return type (int) has a link. - It clearly states what's happening if the range is not defined - It clearly states what's happening if the range contains more than int.max elements On the contrary, the D documentation, introduces a bunch of non-linked concepts, but it tells me that it's possible to perform O(n) evaluations: - isInputRange - isInfiniteRange - hasLength - empty - popFront There is no indication what happens if the range is undefined in D docs. In fact, inconsistent behavior: - it will return 0 in case of null arrays; - it will throw AccessViolation for null ranges (or probably segfault on Linux); There is no indication what happens if the range contains more than size_t.max elements: - integer overflow; Like someone said: D has genius programmers, but worst marketers.
Dec 15 2015
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/15/15 9:03 AM, rumbu wrote:
 On Tuesday, 15 December 2015 at 12:28:02 UTC, ZombineDev wrote:
 On Tuesday, 15 December 2015 at 11:26:04 UTC, rumbu wrote:
 Looking at the .net source code, the Count extension method is also
 doing a best effort "count" by querying the ICollection interface.
Yes, I have looked at the source code, before writing this, so I knew exactly how it worked. In short : terrible, because it relies only on OOP. But that's not the point. Why should anyone need to look at the source code, to see what this function does? I thought this is what the docs were supposed to tell.
 public static int Count<TSource>(this IEnumerable<TSource> [...]

 The Remarks section clearly states the same thing:

 "If the type of source implements ICollection<T>, that implementation
 is used to obtain the count of elements. Otherwise, this method
 determines the count."


 And personally, I found the MS remark more compact and more user
 friendly than:
 [...]
If you look at table at the beginning of page (https://dlang.org/phobos/std_range_primitives.html) you can clearly see a nice concise description of the function. Even if you don't know complexity theory there's the word "Compute" which should give you an idea that the function performs some non-trivial amount of work. Unlike:
 Returns the number of elements in a sequence.
Which implies that it only returns a number - almost like an ordinary getter property. I am scared to think that if back then C# got extension properties, it might have been implemented as such.
 Not everybody is licensed in computational complexity theory to
 understand what O(n) means.
LOL. Personally, I would never want to use any software written by a programmer, who can't tell the difference. Well ok, let's consider a novice programmer who hasn't studied yet complexity theory. Option A: They look at the documentation and see there's some strange O(n) thing that they don't know. They look it up in google and find the wonderful world of complexity theory. They become more educated and are grateful the people who wrote the documentation for describing more accurately the requirements of the function. That way they can easily decide how using such function would impact the performance of their system. Option B: They look at the documentation and see that there's some strange O(n) thing that they don't know. They decide that it's extremely inhumane for the docs to expect such significant knowledge from the reader and they decide to quit. Such novices that do not want to learn are better off choosing a different profession, than inflicting their poor written software on the world.
We are talking about a better documentation, not about the C# vs D performance, we already know the winner. Since C# is an OOP-only language, there is only one way to do reflection - using OOP, (voluntarily ignoring the fact that NGen will reduce this call to a simple memory read in case of arrays). Your affirmation:
 the docs don't even bother to mention that it is almost always O(n),
 because non of the > Enumerable extention methods preserve the
 underlying ICollection interace
was false and you don't need to look to the source code to find out, the Remarks section is self-explanatory: "If the type of source implements ICollection<T>, that implementation is used to obtain the count of elements. Otherwise, this method determines the count." This is a *good* documentation: - "Count" is a better name than "walkLength"; every other programming language will use concepts similar to count, cnt, length, len. - You don't need to understand computer science terms to find out what a function does; - If you are really interested about more than finding out the number of elements, there is a performance hint in the Remarks section. - Links are provided to concepts: even the return type (int) has a link. - It clearly states what's happening if the range is not defined - It clearly states what's happening if the range contains more than int.max elements On the contrary, the D documentation, introduces a bunch of non-linked concepts, but it tells me that it's possible to perform O(n) evaluations: - isInputRange - isInfiniteRange - hasLength - empty - popFront There is no indication what happens if the range is undefined in D docs. In fact, inconsistent behavior: - it will return 0 in case of null arrays; - it will throw AccessViolation for null ranges (or probably segfault on Linux); There is no indication what happens if the range contains more than size_t.max elements: - integer overflow;
This is a great collection of clear points to improve. Thanks! Andrei
Dec 15 2015
prev sibling next sibling parent anonymous <anonymous example.com> writes:
On 15.12.2015 15:03, rumbu wrote:
 There is no indication what happens if the range is undefined in D docs.
 In fact, inconsistent behavior:
 - it will return 0 in case of null arrays;
 - it will throw AccessViolation for null ranges (or probably segfault on
 Linux);
I don't think the behavior is inconsistent. A "null array" is rather different from a null pointer/reference. If anything is inconsistent, I'd say it's the meaning of `null` in the different contexts. A null pointer may be considered "undefined", but a "null array" is certainly not undefined. A "null array" has a null pointer and a length of zero. The zero length makes it so that the null pointer won't be dereferenced. Thinking about arrays in terms of null is probably misleading. Instead, I'd suggest to think in terms of the empty array []. It's the exact same value, but it's more obvious what's going on.
Dec 15 2015
prev sibling next sibling parent reply John Colvin <john.loughran.colvin gmail.com> writes:
On Tuesday, 15 December 2015 at 14:03:50 UTC, rumbu wrote:
 This is a *good* documentation:
 - "Count" is a better name than "walkLength"; every other 
 programming language will use concepts similar to count, cnt, 
 length, len.
meh, I like walkLength. I hate it when a innocuous looking little function does a bunch of expensive work unexpectedly, "walkLength" really points out the worst case. Also, it's important to be reminded that is might actually iterate your range, which the "walk" bit really does, so if it's an inputRange then say goodbye to your data.
 - You don't need to understand computer science terms to find 
 out what a function does;
A little nudge to understand some important concepts never hurts. It can sometimes get a bit obscure though, or be too self-referential (there are probably some non-trivial cycles in the required knowledge graph).
 - If you are really interested about more than finding out the 
 number of elements, there is a performance hint in the Remarks 
 section.
Considering that despite the fact my phone can perform billions of calculations per second but it still takes >2s to open up a text-editor app (on a good day), it seems worthwhile to point out performance a little more forcefully than "here's some other information if you feel like it".
 - Links are provided to concepts: even the return type (int) 
 has a link.

 [ ... ]

 On the contrary, the D documentation, introduces a bunch of 
 non-linked concepts, but it tells me that it's possible to 
 perform O(n) evaluations:
 - isInputRange
 - isInfiniteRange
 - hasLength
 - empty
 - popFront
We should definitely have more links.
 There is no indication what happens if the range is undefined 
 in D docs. In fact, inconsistent behavior:
 - it will return 0 in case of null arrays;
 - it will throw AccessViolation for null ranges (or probably 
 segfault on Linux);
Fair point. I'd love it if phobos range functions treated arrays 100% consistently with custom ranges, but apparently that boat sailed off in multiple directions at once long ago...
Dec 15 2015
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/15/2015 09:40 AM, John Colvin wrote:
 On Tuesday, 15 December 2015 at 14:03:50 UTC, rumbu wrote:
 This is a *good* documentation:
 - "Count" is a better name than "walkLength"; every other programming
 language will use concepts similar to count, cnt, length, len.
meh, I like walkLength.
Me too, but don't forget that nowadays "count" with no predicate defaults to walkLength's semantics. -- Andrei
Dec 15 2015
prev sibling parent reply ZombineDev <valid_email he.re> writes:
On Tuesday, 15 December 2015 at 14:03:50 UTC, rumbu wrote:
 We are talking about a better documentation, not about the C# 
 vs D performance, we already know the winner. Since C# is an 
 OOP-only language, there is only one way to do reflection - 
 using OOP, (voluntarily ignoring the fact that NGen will reduce 
 this call to a simple memory read in case of arrays).

 Your affirmation:

 the docs don't even bother to mention that it is almost always 
 O(n), because non of the Enumerable extention methods preserve 
 the underlying ICollection interace
was false and you don't need to look to the source code to find out, the Remarks section is self-explanatory: "If the type of source implements ICollection<T>, that implementation is used to obtain the count of elements. Otherwise, this method determines the count."
Sorry, I do not know how to make this clear: NONE OF THE System.Linq.Enumerable EXTENSION METHODS PRESERVE THE STRUCTURE (THE INTERFACES THEY IMPLEMENT) OF THE SEQUENCE THEY ARE OPERATING ON. DON'T BELIEVE THAT NGEN WILL AUTOMAGICALLY MAKE YOUR CODE FASTER. IT WILL NOT. UNICORNS DO NOT EXISTS. AT LEAST THEY DO NOT IN .NET OR JAVA. DO NOT BLINDLY BELIEVE. TEST! See for yourself: https://ideone.com/L5FatQ This what I got on my machine: 00:00:00.0011011 for N = 1 -> 1, List<int>.Select(..).Count() 00:00:00.0000017 for N = 2 -> 2, List<int>.Select(..).Count() 00:00:00.0000009 for N = 4 -> 4, List<int>.Select(..).Count() 00:00:00.0000011 for N = 8 -> 8, List<int>.Select(..).Count() 00:00:00.0000012 for N = 16 -> 16, List<int>.Select(..).Count() 00:00:00.0000026 for N = 32 -> 32, List<int>.Select(..).Count() 00:00:00.0000018 for N = 64 -> 64, List<int>.Select(..).Count() 00:00:00.0000032 for N = 128 -> 128, List<int>.Select(..).Count() 00:00:00.0000059 for N = 256 -> 256, List<int>.Select(..).Count() 00:00:00.0000098 for N = 512 -> 512, List<int>.Select(..).Count() 00:00:00.0000190 for N = 1024 -> 1024, List<int>.Select(..).Count() 00:00:00.0000369 for N = 2048 -> 2048, List<int>.Select(..).Count() 00:00:00.0000750 for N = 4096 -> 4096, List<int>.Select(..).Count() 00:00:00.0002185 for N = 8192 -> 8192, List<int>.Select(..).Count() 00:00:00.0003551 for N = 16384 -> 16384, List<int>.Select(..).Count() 00:00:00.0005826 for N = 32768 -> 32768, List<int>.Select(..).Count() 00:00:00.0015252 for N = 65536 -> 65536, List<int>.Select(..).Count() 00:00:00.0024139 for N = 131072 -> 131072, List<int>.Select(..).Count() 00:00:00.0049246 for N = 262144 -> 262144, List<int>.Select(..).Count() 00:00:00.0096537 for N = 524288 -> 524288, List<int>.Select(..).Count() 00:00:00.0194600 for N = 1048576 -> 1048576, List<int>.Select(..).Count() 00:00:00.0422573 for N = 2097152 -> 2097152, List<int>.Select(..).Count() 00:00:00.0749799 for N = 4194304 -> 4194304, List<int>.Select(..).Count() 00:00:00.1511740 for N = 8388608 -> 8388608, List<int>.Select(..).Count() 00:00:00.3004764 for N = 16777216 -> 16777216, List<int>.Select(..).Count() 00:00:00.6018954 for N = 33554432 -> 33554432, List<int>.Select(..).Count() 00:00:01.2064069 for N = 67108864 -> 67108864, List<int>.Select(..).Count() 00:00:02.6716092 for N = 134217728 -> 134217728, List<int>.Select(..).Count() 00:00:05.1524452 for N = 268435456 -> 268435456, List<int>.Select(..).Count() 00:00:09.6481144 for N = 536870912 -> 536870912, List<int>.Select(..).Count() 00:00:00.0005440 for N = 1 -> 1, Array<int>.Select(..).Count() 00:00:00.0000010 for N = 2 -> 2, Array<int>.Select(..).Count() 00:00:00.0000008 for N = 4 -> 4, Array<int>.Select(..).Count() 00:00:00.0000009 for N = 8 -> 8, Array<int>.Select(..).Count() 00:00:00.0000013 for N = 16 -> 16, Array<int>.Select(..).Count() 00:00:00.0000015 for N = 32 -> 32, Array<int>.Select(..).Count() 00:00:00.0000020 for N = 64 -> 64, Array<int>.Select(..).Count() 00:00:00.0000035 for N = 128 -> 128, Array<int>.Select(..).Count() 00:00:00.0000061 for N = 256 -> 256, Array<int>.Select(..).Count() 00:00:00.0000107 for N = 512 -> 512, Array<int>.Select(..).Count() 00:00:00.0000209 for N = 1024 -> 1024, Array<int>.Select(..).Count() 00:00:00.0000424 for N = 2048 -> 2048, Array<int>.Select(..).Count() 00:00:00.0000822 for N = 4096 -> 4096, Array<int>.Select(..).Count() 00:00:00.0001633 for N = 8192 -> 8192, Array<int>.Select(..).Count() 00:00:00.0003263 for N = 16384 -> 16384, Array<int>.Select(..).Count() 00:00:00.0006503 for N = 32768 -> 32768, Array<int>.Select(..).Count() 00:00:00.0013024 for N = 65536 -> 65536, Array<int>.Select(..).Count() 00:00:00.0026130 for N = 131072 -> 131072, Array<int>.Select(..).Count() 00:00:00.0052041 for N = 262144 -> 262144, Array<int>.Select(..).Count() 00:00:00.0103705 for N = 524288 -> 524288, Array<int>.Select(..).Count() 00:00:00.0207945 for N = 1048576 -> 1048576, Array<int>.Select(..).Count() 00:00:00.0418217 for N = 2097152 -> 2097152, Array<int>.Select(..).Count() 00:00:00.0829522 for N = 4194304 -> 4194304, Array<int>.Select(..).Count() 00:00:00.1658241 for N = 8388608 -> 8388608, Array<int>.Select(..).Count() 00:00:00.3304377 for N = 16777216 -> 16777216, Array<int>.Select(..).Count() 00:00:00.6636190 for N = 33554432 -> 33554432, Array<int>.Select(..).Count() 00:00:01.3255121 for N = 67108864 -> 67108864, Array<int>.Select(..).Count() 00:00:02.6572163 for N = 134217728 -> 134217728, Array<int>.Select(..).Count() 00:00:05.2761961 for N = 268435456 -> 268435456, Array<int>.Select(..).Count() 00:00:10.7154543 for N = 536870912 -> 536870912, Array<int>.Select(..).Count()
 This is a *good* documentation:
 - "Count" is a better name than "walkLength"; every other 
 programming language will use concepts similar to count, cnt, 
 length, len.
"Length" is right there in walkLength. I don't see this as an obstacle for anybody that would want to use this function. "walk" in walkLength informs you of the performance consequence, which for me is critical information.
 - You don't need to understand computer science terms to find 
 out what a function does;
A major disadvantage, if you ask me :D BTW, Array.Length uses the same notation: https://msdn.microsoft.com/en-us/library/system.array.length(v=vs.110).aspx
 - If you are really interested about more than finding out the 
 number of elements, there is a performance hint in the Remarks 
 section.
No the Remarks section is so vague that it is no hint: "... Otherwise, this method determines the count" Determines how? I really dislike this the style of documentation written just for the sake documentation.
 - Links are provided to concepts: even the return type (int) 
 has a link.
 - It clearly states what's happening if the range is not defined
 - It clearly states what's happening if the range contains more 
 than int.max elements

 On the contrary, the D documentation, introduces a bunch of 
 non-linked concepts, but it tells me that it's possible to 
 perform O(n) evaluations:
 - isInputRange
 - isInfiniteRange
 - hasLength
 - empty
 - popFront
I agree that Phobos needs to do a lot better at introducing concepts such as ranges.
 There is no indication what happens if the range is undefined 
 in D docs. In fact, inconsistent behavior:
 - it will return 0 in case of null arrays;
This is logical and doesn't need to be documented.
 - it will throw AccessViolation for null ranges (or probably 
 segfault on Linux);
Again, this is expected, as it is a result of a programmer error. Do you document that calling methods on a null object will segfault for every single method? null.Length is not documented for System.Array and doesn't need to be.
 There is no indication what happens if the range contains more 
 than size_t.max elements:
 - integer overflow;
Practically impossible on 64-bit and unlikely that someone will use walkLength with files on 32-bit. It's called *walk*Length for a reason. This is more of an issue in .NET because the length / count is fixed as System.Int32, regardless of the actual amount of addressable memory.
 Like someone said: D has genius programmers, but worst 
 marketers.
Contrary to LINQ which had super good marketing and very bad implementation. I read the blog of one of the guys that worked on Parallel LINQ that there were some instances were you could good get almost 4X improvement with the Parallel version on a 4 CPU system, and then get 100X with a single threaded C implementation :D
Dec 15 2015
parent Chris Wright <dhasenan gmail.com> writes:
On Tue, 15 Dec 2015 15:55:31 +0000, ZombineDev wrote:

 On Tuesday, 15 December 2015 at 14:03:50 UTC, rumbu wrote:
 We are talking about a better documentation, not about the C# vs D
 performance, we already know the winner. Since C# is an OOP-only
 language, there is only one way to do reflection - using OOP,
 (voluntarily ignoring the fact that NGen will reduce this call to a
 simple memory read in case of arrays).

 Your affirmation:

 the docs don't even bother to mention that it is almost always O(n),
 because non of the Enumerable extention methods preserve the
 underlying ICollection interace
was false and you don't need to look to the source code to find out, the Remarks section is self-explanatory: "If the type of source implements ICollection<T>, that implementation is used to obtain the count of elements. Otherwise, this method determines the count."
Sorry, I do not know how to make this clear: NONE OF THE System.Linq.Enumerable EXTENSION METHODS PRESERVE THE STRUCTURE (THE INTERFACES THEY IMPLEMENT) OF THE SEQUENCE THEY ARE OPERATING ON. DON'T BELIEVE THAT NGEN WILL AUTOMAGICALLY MAKE YOUR CODE FASTER. IT WILL NOT. UNICORNS DO NOT EXISTS. AT LEAST THEY DO NOT IN .NET OR JAVA. DO NOT BLINDLY BELIEVE. TEST!
'I said it very loud and clear: I went and shouted in his ear.' Humpty Dumpty raised his voice almost to a scream as he repeated this verse, and Alice thought with a shudder, 'I wouldn't have been the messenger for anything!' 'But he was very stiff and proud: He said, "You needn't shout so loud!" And he was very proud and stiff: He said 'I'd go and wake them, if --"'
 See for yourself: https://ideone.com/L5FatQ
 
 This what I got on my machine:
 00:00:00.0011011 for N = 1 -> 1, List<int>.Select(..).Count()
You have observed that System.Linq hasn't fully propagated metadata about collections through operations where it could and where D's equivalents do. You are blaming this on object oriented programming. It is easy to support a handful of extra operations (like O(1) collection length) on all System.Linq types with object oriented code. It gets harder as you try to support more operations, but there are probably only a few you need to worry about. It is more convenient to use templates and static if, especially as the number of operations grows. But it's certainly possible to do in OOP. You are also explicitly opting out of adaptive optimizations by using ngen. That's a much smaller effect, of course. ngen is better for fast startup and to guarantee that the runtime won't try to re-JIT your code when you're executing code that can't stand for such a pause.
 - You don't need to understand computer science terms to find out what
 a function does;
A major disadvantage, if you ask me :D
"Come learn D, it's actively hostile toward novices!" ...perhaps a different marketing campaign would work better.
 There is no indication what happens if the range contains more than
 size_t.max elements:
 - integer overflow;
Practically impossible on 64-bit and unlikely that someone will use walkLength with files on 32-bit. It's called *walk*Length for a reason.
Not all ranges are backed by data in memory or on disk. I could create a range over the time from the Big Bang to today in 10-femtosecond intervals, for instance. Granted, it would be silly for me to call walkLength on that. Also, there's no indication what the return type is. It could be a short for all I know. Maybe the writer accidentally wrote 'auto count = 0;' instead of explicitly using size_t, in which case by three billion entry range will report that its walk length is negative. I read the source code and know it's using size_t (and should perhaps just be ulong). But it's not documented anywhere.
Dec 15 2015
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 12/15/2015 12:26 PM, rumbu wrote:
 And personally, I found the MS remark more compact and more user
 friendly than:

 "This is a best-effort implementation of length for any kind of range.
 If hasLength!Range, simply returns range.length without checking upTo
 (when specified). Otherwise, walks the range through its length and
 returns the number of elements seen. Performes Ο(n) evaluations of
 range.empty and range.popFront(), where n is the effective length of
 range."

 Not everybody is licensed in computational complexity theory to
 understand what O(n) means.
One doesn't need to know any results or definitions from complexity theory in order to understand what O(n) means. What it means here is that for large enough n the actual number is bounded from above by n multiplied by some unspecified constant. (In contexts like this, there is generally also an informal assumption that the unspecified constants are reasonably small.)
Dec 16 2015
next sibling parent reply "H. S. Teoh via Digitalmars-d" <digitalmars-d puremagic.com> writes:
On Thu, Dec 17, 2015 at 12:00:03AM +0100, Timon Gehr via Digitalmars-d wrote:
 On 12/15/2015 12:26 PM, rumbu wrote:
And personally, I found the MS remark more compact and more user
friendly than:

"This is a best-effort implementation of length for any kind of
range.  If hasLength!Range, simply returns range.length without
checking upTo (when specified). Otherwise, walks the range through
its length and returns the number of elements seen. Performes Ο(n)
evaluations of range.empty and range.popFront(), where n is the
effective length of range."

Not everybody is licensed in computational complexity theory to
understand what O(n) means.
One doesn't need to know any results or definitions from complexity theory in order to understand what O(n) means. What it means here is that for large enough n the actual number is bounded from above by n multiplied by some unspecified constant. (In contexts like this, there is generally also an informal assumption that the unspecified constants are reasonably small.)
Any programmer that has any pretense of caring about the performance of their code ought to know what O(n) means. It's not that hard to understand. There are plenty of online resources to learn about this, even if you didn't have the privilege of having received formal computer science education. T -- "Real programmers can write assembly code in any language. :-)" -- Larry Wall
Dec 16 2015
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Wednesday, 16 December 2015 at 23:02:53 UTC, H. S. Teoh wrote:
 Any programmer that has any pretense of caring about the 
 performance of their code ought to know what O(n) means. It's 
 not that hard to understand. There are plenty of online 
 resources to learn about this, even if you didn't have the 
 privilege of having received formal computer science education.
Yes, just use the term "Worst case time complexity is O(n)". A simple search on google for "time complexity" gives me a nice textual and graphical explanation.
Dec 17 2015
prev sibling parent reply John Colvin <john.loughran.colvin gmail.com> writes:
On Wednesday, 16 December 2015 at 23:00:03 UTC, Timon Gehr wrote:
 On 12/15/2015 12:26 PM, rumbu wrote:
 And personally, I found the MS remark more compact and more 
 user
 friendly than:

 "This is a best-effort implementation of length for any kind 
 of range.
 If hasLength!Range, simply returns range.length without 
 checking upTo
 (when specified). Otherwise, walks the range through its 
 length and
 returns the number of elements seen. Performes Ο(n) 
 evaluations of
 range.empty and range.popFront(), where n is the effective 
 length of
 range."

 Not everybody is licensed in computational complexity theory to
 understand what O(n) means.
One doesn't need to know any results or definitions from complexity theory in order to understand what O(n) means. What it means here is that for large enough n the actual number is bounded from above by n multiplied by some unspecified constant. (In contexts like this, there is generally also an informal assumption that the unspecified constants are reasonably small.)
Perhaps it's the physicist in me, but I like this way of thinking about it: Given a running time R(n), the time-complexity is given by O(f(n)) iff df/dn = lim_{n -> inf} dR(n)/dn Is that also a correct expression? Obviously I'm papering over the discretisation, but well, I did say physicist... :)
Dec 16 2015
next sibling parent jmh530 <john.michael.hall gmail.com> writes:
On Thursday, 17 December 2015 at 00:06:05 UTC, John Colvin wrote:
 Given a running time R(n), the time-complexity is given by 
 O(f(n)) iff df/dn = lim_{n -> inf} dR(n)/dn

 Is that also a correct expression? Obviously I'm papering over 
 the discretisation, but well, I did say physicist... :)
That's how I think about it usually, but I think it's more general than just analyzing run-times of programs. You could use big O notation to classify any kind of function (wikipedia has a more mathematical definition).
Dec 16 2015
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 12/17/2015 01:06 AM, John Colvin wrote:
 One doesn't need to know any results or definitions from complexity
 theory in order to understand what O(n) means. What it means here is
 that for large enough n the actual number is bounded from above by n
 multiplied by some unspecified constant.
 (In contexts like this, there is generally also an informal assumption
 that the unspecified constants are reasonably small.)
Perhaps it's the physicist in me, but I like this way of thinking about it: Given a running time R(n), the time-complexity
I would just say that R(n) is (in) O(f(n)). ('Complexity' does not even imply that the statement that follows talks about asymptotics.)
 is given by  O(f(n)) iff
(Note that O(f(n)) is an upper bound.)
 df/dn = lim_{n -> inf} dR(n)/dn

 Is that also a correct expression?
What this is saying is that for large n, R is approximately a linear polynomial and that f is a linear polynomial with the limiting slope. In particular, 2·n is not in O(n) with this definition and O(n²) is empty. Probably the intended meaning was different.
 Obviously I'm papering over the
 discretisation, but well, I did say physicist... :)
Dec 17 2015
prev sibling parent reply dnewbie <d d.com> writes:
On Tuesday, 15 December 2015 at 09:57:00 UTC, ZombineDev wrote:
 On Monday, 14 December 2015 at 19:56:29 UTC, dnewbie wrote:
 On Monday, 14 December 2015 at 19:04:46 UTC, bachmeier wrote:
 It's unanimous, at least among the three of us posting in 
 this Reddit thread:
 ...
Take for example C# Docs: https://msdn.microsoft.com/en-us/library/system.collections.arraylist.addrange.aspx Syntax C#: public virtual void AddRange( ICollection c ) Parameters: c Type: System.Collections.ICollection The ICollection whose elements should be added to the end of the ArrayList. The collection itself cannot be null, but it can contain elements that are null. Clean, simple and instructive!
You are really comparing apples to oranges...
If you look here: http://forum.dlang.org/post/xiduyyulihesjgjxmgnd forum.dlang.org I said: "but the main focus here was about the simplicity of the layout used in the C# doc. You can see others examples there easily including templates and generics interface." So I was talking about one example vs another, in this case isSameLength, which I suggested something like: Syntax: bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2) Parameters: Type r1, r2 : Input range. Both r1, r2 : needs to be finite. Instead of: bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2) if (isInputRange!Range1 && isInputRange!Range2 && !isInfinite!Range1 && !isInfinite!Range2); But you know I'm newbie... Ron.
Dec 15 2015
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Tuesday, 15 December 2015 at 14:08:34 UTC, dnewbie wrote:
 But you know I'm newbie...
And that makes your input important. Didn't see your response before I wrote mine, but we seem to agree. :)
Dec 15 2015
prev sibling next sibling parent Basile B. <b2.temp gmx.com> writes:
On Monday, 14 December 2015 at 19:04:46 UTC, bachmeier wrote:
 It's unanimous, at least among the three of us posting in this 
 Reddit thread:

 https://www.reddit.com/r/programming/comments/3wqt3p/programming_in_d_ebook_is_at_major_retailers_and/cxyqxuz

 Something has to be done with the documentation for Phobos 
 functions that involve ranges and templates.
Instead of rewriting all the doc I suggest another approach: someone writes a reference article or special phobos page such as "Understanding D ranges, their constraints and the error messages", that could teach how to interpret and undertstand the error messages and the doc. The problem is that new comers really have to learn std.range primitives as well as a big part of std.traits. The article would cover the most encountered functions from this two modules: - isInputRange - isForwardRange - ElementType - isNarrowString - ... Because clearly when you know these functions you understand the constraints. That's the key. ~~~~~~~~~~~~~~~~~~~ Another idea would be to put each condition of a constraint on a new line (I speak about DDoc formating): bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2) if (isInputRange!Range1 && isInputRange!Range2 && !isInfinite!Range1 && !isInfinite!Range2); ~~~~~~~~~~~~~~~~~~~ In the same vein, but a bit better, put the constraint in a separate ddoc section, for example "constraint".
Dec 14 2015
prev sibling next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 12/14/15 2:04 PM, bachmeier wrote:
 It's unanimous, at least among the three of us posting in this Reddit
 thread:

 https://www.reddit.com/r/programming/comments/3wqt3p/programming_in_d_ebook_is_at_major_retailers_and/cxyqxuz


 Something has to be done with the documentation for Phobos functions
 that involve ranges and templates. The example I gave there is

 bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2) if
 (isInputRange!Range1 && isInputRange!Range2 && !isInfinite!Range1 &&
 !isInfinite!Range2);
This is by far, one of the least problematic examples. A while back, I wanted to use std.algorithm.find to search for something. I wasn't sure what order to call the parameters with, so I looked at the documentation. After about 10-15 minutes of trying to deduce whatever template overload was going to match, if any at all, I just decided to write the call and see if it worked (it did). The documentation for IFTI functions like this needs to be simplified greatly. Essentially, I need to know what types of things I can use, and what order I need to pass them. But I don't need all the details of which overload will be called depending on some obscure template constraint. I don't know if there's an automated way to do this. IFTI functions are so powerfully useful, that it's almost impossible to have this done automatically. In the example of find, a possible way to do this is to wrap the whole set of overloads into one simplified call: Range1 find(Range1 haystack, N needle) And then explain what Range1 and N can be. Then allow one to expand the docs to see all the true signatures if I want to. In std.conv, there is a global template to that forwards to all the different toImpl, with the majority of docs on the to template. That is kind of the model I was thinking of, but allow ddoc to hide all the implementation details and show on demand. -Steve
Dec 14 2015
parent reply Chris Wright <dhasenan gmail.com> writes:
On Mon, 14 Dec 2015 18:45:28 -0500, Steven Schveighoffer wrote:

 On 12/14/15 2:04 PM, bachmeier wrote:
 It's unanimous, at least among the three of us posting in this Reddit
 thread:

 https://www.reddit.com/r/programming/comments/3wqt3p/
programming_in_d_ebook_is_at_major_retailers_and/cxyqxuz
 Something has to be done with the documentation for Phobos functions
 that involve ranges and templates. The example I gave there is

 bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2) if
 (isInputRange!Range1 && isInputRange!Range2 && !isInfinite!Range1 &&
 !isInfinite!Range2);
This is by far, one of the least problematic examples. A while back, I wanted to use std.algorithm.find to search for something. I wasn't sure what order to call the parameters with, so I looked at the documentation. After about 10-15 minutes of trying to deduce whatever template overload was going to match, if any at all, I just decided to write the call and see if it worked (it did). The documentation for IFTI functions like this needs to be simplified greatly. Essentially, I need to know what types of things I can use, and what order I need to pass them. But I don't need all the details of which overload will be called depending on some obscure template constraint. I don't know if there's an automated way to do this. IFTI functions are so powerfully useful, that it's almost impossible to have this done automatically. In the example of find, a possible way to do this is to wrap the whole set of overloads into one simplified call: Range1 find(Range1 haystack, N needle) And then explain what Range1 and N can be. Then allow one to expand the docs to see all the true signatures if I want to.
This reminds me of the Tango strategy for this kind of thing. tango.core.Array was arranged like this: version(TangoDoc) { /** Documentation comment. */ bool isSameLangth(Range1, Range2)(Range1 r1, Range2 r2) { return true; } } else { bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2) if ( isInputRange!Range1 && isInputRange!Range2 && !isInfinite!Range1 && !isInfinite!Range2) { // actual implementation } } Of course, this was before template constraints -- which in turn means that the templates they were doing this for were much more succinct than what you find in std.algorithm, and they still felt it important to simplify for the sake of documentation. It's not ideal because it relies on prose documentation, which might be far from the implementation, to stay up to date. On the other hand, it's something that can be done today, without any changes to ddoc. An outer template that forwards to specialized templates would be cleaner.
Dec 14 2015
next sibling parent reply tcak <1ltkrs+3wyh1ow7kzn1k sharklasers.com> writes:
On Tuesday, 15 December 2015 at 01:10:01 UTC, Chris Wright wrote:
 On Mon, 14 Dec 2015 18:45:28 -0500, Steven Schveighoffer wrote:

 On 12/14/15 2:04 PM, bachmeier wrote:
 It's unanimous, at least among the three of us posting in 
 this Reddit thread:

 https://www.reddit.com/r/programming/comments/3wqt3p/
programming_in_d_ebook_is_at_major_retailers_and/cxyqxuz
 Something has to be done with the documentation for Phobos 
 functions that involve ranges and templates. The example I 
 gave there is

 bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2) if
 (isInputRange!Range1 && isInputRange!Range2 && 
 !isInfinite!Range1 &&
 !isInfinite!Range2);
This is by far, one of the least problematic examples. A while back, I wanted to use std.algorithm.find to search for something. I wasn't sure what order to call the parameters with, so I looked at the documentation. After about 10-15 minutes of trying to deduce whatever template overload was going to match, if any at all, I just decided to write the call and see if it worked (it did). The documentation for IFTI functions like this needs to be simplified greatly. Essentially, I need to know what types of things I can use, and what order I need to pass them. But I don't need all the details of which overload will be called depending on some obscure template constraint. I don't know if there's an automated way to do this. IFTI functions are so powerfully useful, that it's almost impossible to have this done automatically. In the example of find, a possible way to do this is to wrap the whole set of overloads into one simplified call: Range1 find(Range1 haystack, N needle) And then explain what Range1 and N can be. Then allow one to expand the docs to see all the true signatures if I want to.
This reminds me of the Tango strategy for this kind of thing. tango.core.Array was arranged like this: version(TangoDoc) { /** Documentation comment. */ bool isSameLangth(Range1, Range2)(Range1 r1, Range2 r2) { return true; } } else { bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2) if ( isInputRange!Range1 && isInputRange!Range2 && !isInfinite!Range1 && !isInfinite!Range2) { // actual implementation } } Of course, this was before template constraints -- which in turn means that the templates they were doing this for were much more succinct than what you find in std.algorithm, and they still felt it important to simplify for the sake of documentation. It's not ideal because it relies on prose documentation, which might be far from the implementation, to stay up to date. On the other hand, it's something that can be done today, without any changes to ddoc. An outer template that forwards to specialized templates would be cleaner.
Hiding conditionals does not seem like to be solution. Here is my idea: Show the function: bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2) Then show the conditions separately: if( isInputRange!Range1 && isInputRange!Range2 && !isInfinite!Range1 && !isInfinite!Range2 ) I am not sure whether ddoc supports/can support this, but being able to do this, and even adding separate comment on function and its conditionals separately could be quite useful. I know just talking doesn't make anything working, but idea is needed first. By the way, I wish "and", "or", "xor" were in the language as in Pascal. Things could be more human friendly maybe.
Dec 14 2015
next sibling parent cym13 <cpicard openmailbox.org> writes:
On Tuesday, 15 December 2015 at 01:50:07 UTC, tcak wrote:
 On Tuesday, 15 December 2015 at 01:10:01 UTC, Chris Wright 
 wrote:
 [...]
Hiding conditionals does not seem like to be solution. Here is my idea: Show the function: bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2) Then show the conditions separately: if( isInputRange!Range1 && isInputRange!Range2 && !isInfinite!Range1 && !isInfinite!Range2 ) I am not sure whether ddoc supports/can support this, but being able to do this, and even adding separate comment on function and its conditionals separately could be quite useful. I know just talking doesn't make anything working, but idea is needed first. By the way, I wish "and", "or", "xor" were in the language as in Pascal. Things could be more human friendly maybe.
I think a first step can be taken that doesn't even need changing DDOC's output: just add syntax highlighting to the line in order to emphasize "bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2)" and make it look distinct from the template constraint part. It won't solve every problems but to a beginners eye it reads like "this is what the important stuff is".
Dec 14 2015
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 12/14/15 8:50 PM, tcak wrote:
 Hiding conditionals does not seem like to be solution. Here is my idea:

 Show the function:
 bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2)

 Then show the conditions separately:
 if(
    isInputRange!Range1 &&
    isInputRange!Range2 &&
    !isInfinite!Range1 &&
    !isInfinite!Range2
 )
Here are all the overloads of find (each with differing documentation): InputRange find(alias pred = "a == b", InputRange, Element)(InputRange haystack, Element needle) if (isInputRange!InputRange && is(typeof(binaryFun!pred(haystack.front, needle)) : bool)); InputRange find(alias pred, InputRange)(InputRange haystack) if (isInputRange!InputRange); R1 find(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle) if (isForwardRange!R1 && isForwardRange!R2 && is(typeof(binaryFun!pred(haystack.front, needle.front)) : bool) && !isRandomAccessRange!R1); Tuple!(Range, size_t) find(alias pred = "a == b", Range, Ranges...)(Range haystack, Ranges needles) if (Ranges.length > 1 && is(typeof(startsWith!pred(haystack, needles)))); Range1 find(Range1, alias pred, Range2)(Range1 haystack, BoyerMooreFinder!(pred, Range2) needle); If you can decipher this into what find actually will accept, then you have more patience than me. I think what I wanted (it's difficult to remember) is whether I could pass in a subrange for find to search for as the needle. It appears to reject cases where the haystack is a random access range and the needle is a range (but it does work). My take is that the user only needs to know that if he wants to find a needle in a haystack, he does: auto result = find(haystack, needle [, needle2, ...]); Find will handle just about any call you can think of. How can the docs just say this concisely? -Steve
Dec 14 2015
next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 12/14/15 9:34 PM, Steven Schveighoffer wrote:
 InputRange find(alias pred = "a == b", InputRange, Element)(InputRange
 haystack, Element needle) if (isInputRange!InputRange &&
 is(typeof(binaryFun!pred(haystack.front, needle)) : bool));
 InputRange find(alias pred, InputRange)(InputRange haystack) if
 (isInputRange!InputRange);
 R1 find(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle) if
 (isForwardRange!R1 && isForwardRange!R2 &&
 is(typeof(binaryFun!pred(haystack.front, needle.front)) : bool) &&
 !isRandomAccessRange!R1);
 Tuple!(Range, size_t) find(alias pred = "a == b", Range,
 Ranges...)(Range haystack, Ranges needles) if (Ranges.length > 1 &&
 is(typeof(startsWith!pred(haystack, needles))));
 Range1 find(Range1, alias pred, Range2)(Range1 haystack,
 BoyerMooreFinder!(pred, Range2) needle);

 If you can decipher this into what find actually will accept, then you
 have more patience than me. I think what I wanted (it's difficult to
 remember) is whether I could pass in a subrange for find to search for
 as the needle. It appears to reject cases where the haystack is a random
 access range and the needle is a range (but it does work).
Heh, looking at the source, I see I was a victim of improper documentation. There are 2 additional overloads of find that are NOT DOCUMENTED. It's likely that the 2 overloads vary only by constraints, and that's why they are not documented. But as a user, again, I shouldn't have to care what the constraints are specifically. -Steve
Dec 14 2015
parent reply landaire <landergriffith+dlang gmail.com> writes:
On Tuesday, 15 December 2015 at 02:39:16 UTC, Steven 
Schveighoffer wrote:
 On 12/14/15 9:34 PM, Steven Schveighoffer wrote:
 InputRange find(alias pred = "a == b", InputRange, 
 Element)(InputRange
 haystack, Element needle) if (isInputRange!InputRange &&
 is(typeof(binaryFun!pred(haystack.front, needle)) : bool));
 InputRange find(alias pred, InputRange)(InputRange haystack) if
 (isInputRange!InputRange);
 R1 find(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle) 
 if
 (isForwardRange!R1 && isForwardRange!R2 &&
 is(typeof(binaryFun!pred(haystack.front, needle.front)) : 
 bool) &&
 !isRandomAccessRange!R1);
 Tuple!(Range, size_t) find(alias pred = "a == b", Range,
 Ranges...)(Range haystack, Ranges needles) if (Ranges.length > 
 1 &&
 is(typeof(startsWith!pred(haystack, needles))));
 Range1 find(Range1, alias pred, Range2)(Range1 haystack,
 BoyerMooreFinder!(pred, Range2) needle);

 If you can decipher this into what find actually will accept, 
 then you
 have more patience than me. I think what I wanted (it's 
 difficult to
 remember) is whether I could pass in a subrange for find to 
 search for
 as the needle. It appears to reject cases where the haystack 
 is a random
 access range and the needle is a range (but it does work).
Heh, looking at the source, I see I was a victim of improper documentation. There are 2 additional overloads of find that are NOT DOCUMENTED. It's likely that the 2 overloads vary only by constraints, and that's why they are not documented. But as a user, again, I shouldn't have to care what the constraints are specifically. -Steve
I started exploring D a couple of months ago and I was the original poster in the reddit thread who sparked this discussion. While on the topic of documentation I wanted to quickly put in my thoughts about what frustrated me with the documentation: - I didn't understand the visual hierarchy for templates at first. e.g. canFind: https://dlang.org/phobos/std_algorithm_searching.html#canFind. I don't remember the exact examples but I had to look at the source code to understand what this was trying to show me - Runnable examples would be *so* useful! They're present on the homepage, why can't the examples provided in the inline docs be runnable as well? - Linking types, functions, etc. in the function signatures would be great *if possible*. e.g.: bool startsWith(alias pred = "a == b", R1, R2)(R1 doesThisStart, R2 withThis) if (isInputRange!R1 && isInputRange!R2 && is(typeof(binaryFun!pred(doesThisStart.front, withThis.front)) : bool)); Make bool, isInputRange, typeof, and binaryFun all links to their definitions. If I don't know what "isInputRange" does, do I really have to go spend more time to figure out where it lives? - Add another line break between overloaded methods! Having no separation between lines makes things very difficult to sort out Here's an imgur album I created to show some suggestions for function signatures: http://imgur.com/a/njHKI - Dead links = compile error when compiling documentation? This was annoying when trying to find out more about OutputRanges. The only resource I found was on the std.range page in the tee definition, and the link was dead: http://dlang.org/phobos/std_range.html#.tee - Link to where the code is implemented in Phobos at the time of compilation. e.g. clicking the actual name of "find" could link me here: https://github.com/D-Programming-Language/phobos/blob/b6a61d9e719a9d680936db44b98fbb5dd28bf6b1/std/algorith /searching.d#L1498. More than once I found that reading the code was more useful than reading the documentation. I find that I learn best by reading documentation. Go's documentation is phenomenal and it's very easy to follow and understand (yes, I realize this is kind of comparing apples to oranges in terms of complexity). I don't want to have to have to read documentation on understanding the documentation. I'm currently on winter break from university and would love to help contribute some of these changes if people think they're useful as well.
Dec 15 2015
next sibling parent reply landaire <landergriffith+dlang gmail.com> writes:
On Tuesday, 15 December 2015 at 08:08:10 UTC, landaire wrote:
 I started exploring D a couple of months ago and I was the 
 original poster in the reddit thread who sparked this 
 discussion. While on the topic of documentation I wanted to 
 quickly put in my thoughts about what frustrated me with the 
 documentation:

 [...]
Dang, no responses to this?
Dec 15 2015
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/15/2015 11:24 AM, landaire wrote:
 On Tuesday, 15 December 2015 at 08:08:10 UTC, landaire wrote:
 I started exploring D a couple of months ago and I was the original
 poster in the reddit thread who sparked this discussion. While on the
 topic of documentation I wanted to quickly put in my thoughts about
 what frustrated me with the documentation:

 [...]
Dang, no responses to this?
I started a long answer and then my Ubuntu froze. Will redo it... -- Andrei
Dec 15 2015
prev sibling next sibling parent Jack Stouffer <jack jackstouffer.com> writes:
On Tuesday, 15 December 2015 at 08:08:10 UTC, landaire wrote:
 - Runnable examples would be *so* useful! They're present on 
 the homepage, why can't the examples provided in the inline 
 docs be runnable as well?
[snip]
 Here's an imgur album I created to show some suggestions for 
 function signatures: http://imgur.com/a/njHKI
These are all great suggestions. Please add them to the bug report already mentioned in this thread.
 - Dead links = compile error when compiling documentation? This 
 was annoying when trying to find out more about OutputRanges. 
 The only resource I found was on the std.range page in the tee 
 definition, and the link was dead: 
 http://dlang.org/phobos/std_range.html#.tee
I think CyberShadow was working on this. It is a problem though that needs fixing.
 - Link to where the code is implemented in Phobos at the time 
 of compilation. e.g. clicking the actual name of "find" could 
 link me here: 
 https://github.com/D-Programming-Language/phobos/blob/b6a61d9e719a9d680936db44b98fbb5dd28bf6b1/std/algorith
/searching.d#L1498. More than once I found that reading the code was more
useful than reading the documentation.
Also a good idea.
Dec 15 2015
prev sibling next sibling parent wobbles <grogan.colin gmail.com> writes:
On Tuesday, 15 December 2015 at 08:08:10 UTC, landaire wrote:
 On Tuesday, 15 December 2015 at 02:39:16 UTC, Steven 
 Schveighoffer wrote:
 [...]
I started exploring D a couple of months ago and I was the original poster in the reddit thread who sparked this discussion. While on the topic of documentation I wanted to quickly put in my thoughts about what frustrated me with the documentation: [...]
I think these are some great suggestions, particularly the 3rd example where the function signature is emphasized.
Dec 15 2015
prev sibling next sibling parent bachmeier <no spam.com> writes:
On Tuesday, 15 December 2015 at 08:08:10 UTC, landaire wrote:

 Here's an imgur album I created to show some suggestions for 
 function signatures: http://imgur.com/a/njHKI
I really like the one titled "Put more emphasis on the function signature". With proper spacing and reducing the noise caused by the constraints, it's actually readable.
Dec 15 2015
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/15/2015 03:08 AM, landaire wrote:
 - Runnable examples would be *so* useful! They're present on the
 homepage, why can't the examples provided in the inline docs be runnable
 as well?
The runnable examples were first provided by nazriel (he's to be found around here and on IRC). He also started to expand runnable examples, but then got busy with other things. This would be a great project.
 - Linking types, functions, etc. in the function signatures would be
 great *if possible*. e.g.:

 bool startsWith(alias pred = "a == b", R1, R2)(R1 doesThisStart, R2
 withThis) if (isInputRange!R1 && isInputRange!R2 &&
 is(typeof(binaryFun!pred(doesThisStart.front, withThis.front)) : bool));

 Make bool, isInputRange, typeof, and binaryFun all links to their
 definitions. If I don't know what "isInputRange" does, do I really have
 to go spend more time to figure out where it lives?
This is a good idea that would require changes to ddoc.
 - Add another line break between overloaded methods! Having no
 separation between lines makes things very difficult to sort out
This is easy. You need to figure out what separator ddoc introduces between overloads. "make verbatim" in dlang.org was conceived exactly for that kind of stuff.
 Here's an imgur album I created to show some suggestions for function
 signatures: http://imgur.com/a/njHKI

 - Dead links = compile error when compiling documentation? This was
 annoying when trying to find out more about OutputRanges. The only
 resource I found was on the std.range page in the tee definition, and
 the link was dead: http://dlang.org/phobos/std_range.html#.tee
There are a number of dead link detectors, online and offline. We just haven't integrated any although Vladimir was looking into it at a point. This would be a fine project to get into, too.
 - Link to where the code is implemented in Phobos at the time of
 compilation. e.g. clicking the actual name of "find" could link me here:
 https://github.com/D-Programming-Language/phobos/blob/b6a61d9e719a9d680936db44b98fbb5dd28bf6b1/std/algorithm/searching.d#L1498.
 More than once I found that reading the code was more useful than
 reading the documentation.
We already have a SOURCE macro for that I think.
 I find that I learn best by reading documentation. Go's documentation is
 phenomenal and it's very easy to follow and understand (yes, I realize
 this is kind of comparing apples to oranges in terms of complexity). I
 don't want to have to have to read documentation on understanding the
 documentation.

 I'm currently on winter break from university and would love to help
 contribute some of these changes if people think they're useful as well.
I suggest you start with the simpler stuff, such as better formatting of overloads. That'll allow you to find your way around the doc build and see what the macros are and what they generate. It'd be great if you got the verbatim build going, it's seldom used but very helpful. Make some css changes while at it. Then move into more involved stuff. Overall doc building is a territory where there's plenty of easy-hanging fruit, and the satisfaction is high. I have a great time whenever I get into it, just less often than I wish. Andrei
Dec 15 2015
parent landaire <landergriffith+dlang gmail.com> writes:
On Tuesday, 15 December 2015 at 19:51:37 UTC, Andrei Alexandrescu 
wrote:
 I suggest you start with the simpler stuff, such as better 
 formatting of overloads. That'll allow you to find your way 
 around the doc build and see what the macros are and what they 
 generate. It'd be great if you got the verbatim build going, 
 it's seldom used but very helpful. Make some css changes while 
 at it. Then move into more involved stuff.

 Overall doc building is a territory where there's plenty of 
 easy-hanging fruit, and the satisfaction is high. I have a 
 great time whenever I get into it, just less often than I wish.


 Andrei
Thanks for the feedback Andrei and everyone else. I'll start stabbing at things this weekend. Setting up the site in a vagrant environment shouldn't be too difficult. I don't want to shoot for too much but I'll also see about setting up a staging environment on my server to display the changes on.
Dec 15 2015
prev sibling next sibling parent carljv <carljv gmail.com> writes:
On Tuesday, 15 December 2015 at 02:34:01 UTC, Steven 
Schveighoffer wrote:
 Find will handle just about any call you can think of. How can 
 the docs just say this concisely?

 -Steve
I think it's an interesting question to what extent template constraints are actually suitable at all as human documentation. Should treat them as part of the source and hide them? I mean, the documentation doesn't include in and out contract conditions of functions, which I think are quite close to what template constraints are: important information for the compiler, somewhat important information for special uses, and mostly ignorable in day to day use. I find many template constraints to be obvious; I know I can't ask for the length of an infinite range (the library writer is just letting the compiler know). Therefore, giving them prominence in the documentation often makes a lot of noise. There's a spectrum of things from the source code we include in documentation. The body of the function, no. Argument and return types, yes. Where do template constraints fit into this spectrum? If we allow for prose documentation of template constraints, should the implementation still be displayed? In how many cases is there a clear information gain?
Dec 14 2015
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/14/15 9:34 PM, Steven Schveighoffer wrote:
 On 12/14/15 8:50 PM, tcak wrote:
 Hiding conditionals does not seem like to be solution. Here is my idea:

 Show the function:
 bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2)

 Then show the conditions separately:
 if(
    isInputRange!Range1 &&
    isInputRange!Range2 &&
    !isInfinite!Range1 &&
    !isInfinite!Range2
 )
Here are all the overloads of find (each with differing documentation): InputRange find(alias pred = "a == b", InputRange, Element)(InputRange haystack, Element needle) if (isInputRange!InputRange && is(typeof(binaryFun!pred(haystack.front, needle)) : bool)); InputRange find(alias pred, InputRange)(InputRange haystack) if (isInputRange!InputRange); R1 find(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle) if (isForwardRange!R1 && isForwardRange!R2 && is(typeof(binaryFun!pred(haystack.front, needle.front)) : bool) && !isRandomAccessRange!R1); Tuple!(Range, size_t) find(alias pred = "a == b", Range, Ranges...)(Range haystack, Ranges needles) if (Ranges.length > 1 && is(typeof(startsWith!pred(haystack, needles)))); Range1 find(Range1, alias pred, Range2)(Range1 haystack, BoyerMooreFinder!(pred, Range2) needle); If you can decipher this into what find actually will accept, then you have more patience than me. I think what I wanted (it's difficult to remember) is whether I could pass in a subrange for find to search for as the needle. It appears to reject cases where the haystack is a random access range and the needle is a range (but it does work). My take is that the user only needs to know that if he wants to find a needle in a haystack, he does: auto result = find(haystack, needle [, needle2, ...]); Find will handle just about any call you can think of. How can the docs just say this concisely?
This function (immensely useful, very general) is a very good archetype for thinking how to structure documentation properly. One good start would be to deconstruct the would-be documentation into components. Where do we want to list the overloads? How about the template parameters? The constraints? Examples? Free text? A mock-up of "The Great Page for find()" would be useful. Andrei
Dec 14 2015
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/14/15 8:10 PM, Chris Wright wrote:
 version(TangoDoc) {
    /** Documentation comment. */
    bool isSameLangth(Range1, Range2)(Range1 r1, Range2 r2) {
      return true;
    }
 } else {
    bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2)
      if (
        isInputRange!Range1 &&
        isInputRange!Range2 &&
        !isInfinite!Range1 &&
        !isInfinite!Range2) {
      // actual implementation
    }
 }
We use this pattern in only a couple of places in Phobos, but I think we should generally improve the language to use less, not more, of it. BTW I think all overloads of a given function should be under the same DDOC entry with nice descriptions of what cases they apply to. The situation right now with many function having separately-documented overloads with "Jump to: 2" etc. is undesirable. Andrei
Dec 14 2015
parent reply Jakob Ovrum <jakobovrum gmail.com> writes:
On Tuesday, 15 December 2015 at 03:47:30 UTC, Andrei Alexandrescu 
wrote:
 We use this pattern in only a couple of places in Phobos, but I 
 think we should generally improve the language to use less, not 
 more, of it.

 BTW I think all overloads of a given function should be under 
 the same DDOC entry with nice descriptions of what cases they 
 apply to. The situation right now with many function having 
 separately-documented overloads with "Jump to: 2" etc. is 
 undesirable.


 Andrei
One possible trick is to use multiple `Params:` sections. Optional parameters can be described as such in the parameter description to reduce the number of `Params:` sections needed. Another thing we should do is simplify our overload sets/template constraints. For example, `find` has two overloads for needle search which can be collapsed into one. They have different template constraints - but only because of practical limitations in constraining all the needles properly, which should be remedied with improvements to std.traits and std.meta.
Dec 14 2015
next sibling parent Jacob Carlborg <doob me.com> writes:
On 2015-12-15 04:51, Jakob Ovrum wrote:

 One possible trick is to use multiple `Params:` sections. Optional
 parameters can be described as such in the parameter description to
 reduce the number of `Params:` sections needed.
Yardoc, used in the Ruby world, allows to do something similar. It has the "overload" tag [1] which allows you specify multiple signatures, including parameters, in the documentation for a single method in the source code. I should add that Ruby doesn't support overloading methods. [1] http://www.rubydoc.info/gems/yard/file/docs/Tags.md#overload -- /Jacob Carlborg
Dec 15 2015
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/14/15 10:51 PM, Jakob Ovrum wrote:
 On Tuesday, 15 December 2015 at 03:47:30 UTC, Andrei Alexandrescu wrote:
 We use this pattern in only a couple of places in Phobos, but I think
 we should generally improve the language to use less, not more, of it.

 BTW I think all overloads of a given function should be under the same
 DDOC entry with nice descriptions of what cases they apply to. The
 situation right now with many function having separately-documented
 overloads with "Jump to: 2" etc. is undesirable.


 Andrei
One possible trick is to use multiple `Params:` sections. Optional parameters can be described as such in the parameter description to reduce the number of `Params:` sections needed. Another thing we should do is simplify our overload sets/template constraints. For example, `find` has two overloads for needle search which can be collapsed into one. They have different template constraints - but only because of practical limitations in constraining all the needles properly, which should be remedied with improvements to std.traits and std.meta.
Yah, these are sensible ideas. Please add them to https://issues.dlang.org/show_bug.cgi?id=13676. Thanks! -- Andrei
Dec 15 2015
prev sibling parent reply Adrian Matoga <epi atari8.info> writes:
On Tuesday, 15 December 2015 at 01:10:01 UTC, Chris Wright wrote:
 This reminds me of the Tango strategy for this kind of thing.

 tango.core.Array was arranged like this:

 version(TangoDoc) {
   /** Documentation comment. */
   bool isSameLangth(Range1, Range2)(Range1 r1, Range2 r2) {
     return true;
   }
 } else {
   bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2)
     if (
       isInputRange!Range1 &&
       isInputRange!Range2 &&
       !isInfinite!Range1 &&
       !isInfinite!Range2) {
     // actual implementation
   }
 }
Fantastic example of why this strategy should be just banned. You need to duplicate the signature in the source, and you are free to make any mistake that won't be caught by the compiler, such as the typo in the word 'Length' here. A beginner then copies the signature and fills in the argument part, and then spends minutes decrypting error messages or even grepping Phobos source to find out that the name of the function should be spelled 'isSameLength', as it's quite easy to overlook, especially when you copy-paste from the official documentation, which you expect to be correct.
Dec 15 2015
parent reply Chris Wright <dhasenan gmail.com> writes:
On Tue, 15 Dec 2015 09:09:43 +0000, Adrian Matoga wrote:

 Fantastic example of why this strategy should be just banned. 
Just as well I wasn't recommending it as a long-term solution. I was more offering it as additional evidence that template definitions can get a bit large and people have known that this is a problem for documentation for eight years now. "Banned" is a strong term. Perhaps you simply meant it should not be recommended and should not be used in Phobos?
Dec 15 2015
parent Adrian Matoga <epi atari8.info> writes:
On Tuesday, 15 December 2015 at 16:12:18 UTC, Chris Wright wrote:
 On Tue, 15 Dec 2015 09:09:43 +0000, Adrian Matoga wrote:

 Fantastic example of why this strategy should be just banned.
Just as well I wasn't recommending it as a long-term solution. I was more offering it as additional evidence that template definitions can get a bit large and people have known that this is a problem for documentation for eight years now. "Banned" is a strong term. Perhaps you simply meant it should not be recommended and should not be used in Phobos?
Yes, perhaps "strongly discouraged" would be a more appropriate wording. version(StdDdoc) already appears about 40 times in Phobos, sometimes wrapping quite large blocks of declarations. I doubt the maintainability of such setup in the long term.
Dec 15 2015
prev sibling next sibling parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Monday, 14 December 2015 at 19:04:46 UTC, bachmeier wrote:
 Something has to be done with the documentation for Phobos 
 functions that involve ranges and templates. The example I gave 
 there is

 bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2) if 
 (isInputRange!Range1 && isInputRange!Range2 && 
 !isInfinite!Range1 && !isInfinite!Range2);

 Unfortunately, that's less ugly than for a lot of functions. In 
 some circumstances, I can see something like that reminding the 
 author of the function about some details, but it can only 
 confuse anyone else.

 There is nothing I can do about this. Who makes these 
 decisions? Can we change it to something useful?
Maybe just try to write up some examples of what it could look like. The full signature could be an expandable section and hidden from newbies. " bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2) if (isInputRange!Range1 && isInputRange!Range2 && !isInfinite!Range1 && !isInfinite!Range2); " Could be something like this: " isSameLength(r1, r2) -> bool r1,r2 : finite input range " with a "+" icon in the margin to see the formal description.
Dec 15 2015
prev sibling next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
Just something I want to throw out as a reminder, a part of the 
ranges chapter of my book is public on the packt website:

https://www.packtpub.com/books/content/ranges

and a longer things from Mike Parker's book is too:

https://www.packtpub.com/books/content/understanding-ranges

a lot of us have talked about ranges, it all ought to be nicely 
referenced in the docs as much as we can.
Dec 15 2015
parent bachmeier <no spam.com> writes:
On Tuesday, 15 December 2015 at 14:41:34 UTC, Adam D. Ruppe wrote:
 Just something I want to throw out as a reminder, a part of the 
 ranges chapter of my book is public on the packt website:

 https://www.packtpub.com/books/content/ranges

 and a longer things from Mike Parker's book is too:

 https://www.packtpub.com/books/content/understanding-ranges

 a lot of us have talked about ranges, it all ought to be nicely 
 referenced in the docs as much as we can.
Are those links permanent, so that we don't have to worry about broken links in the future?
Dec 15 2015
prev sibling next sibling parent reply wobbles <grogan.colin gmail.com> writes:
On Monday, 14 December 2015 at 19:04:46 UTC, bachmeier wrote:
 It's unanimous, at least among the three of us posting in this 
 Reddit thread:

 https://www.reddit.com/r/programming/comments/3wqt3p/programming_in_d_ebook_is_at_major_retailers_and/cxyqxuz

 Something has to be done with the documentation for Phobos 
 functions that involve ranges and templates. The example I gave 
 there is

 bool isSameLength(Range1, Range2)(Range1 r1, Range2 r2) if 
 (isInputRange!Range1 && isInputRange!Range2 && 
 !isInfinite!Range1 && !isInfinite!Range2);

 Unfortunately, that's less ugly than for a lot of functions. In 
 some circumstances, I can see something like that reminding the 
 author of the function about some details, but it can only 
 confuse anyone else.

 There is nothing I can do about this. Who makes these 
 decisions? Can we change it to something useful?

 Also, I think the documentation for functions involving ranges 
 needs more "for dummies" examples. Too many of those functions 
 leave the reader not having a clue what to do after calling the 
 function. I know how that can be fixed.
I think that most of the problem is simply down to how the documentation looks. It's too dense. I think some whitespace and some color-coding will go a long way to making the function signatures better. bool isSameLength (Range1, Range2) // a grey color (Range1 r1, Range2 r2) // a blue if (isInputRange!Range1 && isInputRange!Range2 && !isInfinite!Range1 && !isInfinite!Range2); // same grey color as template args, to point out they're working on the template I think that would make all documentation much easier to glance over, and yet easy to read if you need to. On the examples - more examples can only be better!
Dec 15 2015
parent Chris Wright <dhasenan gmail.com> writes:
On Tue, 15 Dec 2015 16:10:49 +0000, wobbles wrote:

 I think some whitespace and some color-coding will go a long way to
 making the function signatures better.
We'll want to make sure we test with color-blindness filters, of course.
Dec 15 2015
prev sibling next sibling parent reply =?UTF-8?B?THXDrXM=?= Marques <luis luismarques.eu> writes:
On Monday, 14 December 2015 at 19:04:46 UTC, bachmeier wrote:
 Something has to be done with the documentation for Phobos 
 functions that involve ranges and templates.
Just today: - "Where's the documentation for makeIndex?" - http://imgur.com/4SQckvN - "AHHHHHH!" *runs away*
Dec 16 2015
next sibling parent landaire <landergriffith+dlang gmail.com> writes:
On Wednesday, 16 December 2015 at 18:25:31 UTC, Luís Marques 
wrote:
 On Monday, 14 December 2015 at 19:04:46 UTC, bachmeier wrote:
 Something has to be done with the documentation for Phobos 
 functions that involve ranges and templates.
Just today: - "Where's the documentation for makeIndex?" - http://imgur.com/4SQckvN - "AHHHHHH!" *runs away*
I've proposed a few changes to dlang.org and dmd that should help with this: https://github.com/D-Programming-Language/dlang.org/pull/1169 https://github.com/D-Programming-Language/dmd/pull/5311
Dec 16 2015
prev sibling parent tcak <1ltkrs+3wyh1ow7kzn1k sharklasers.com> writes:
On Wednesday, 16 December 2015 at 18:25:31 UTC, Luís Marques 
wrote:
 On Monday, 14 December 2015 at 19:04:46 UTC, bachmeier wrote:
 Something has to be done with the documentation for Phobos 
 functions that involve ranges and templates.
Just today: - "Where's the documentation for makeIndex?" - http://imgur.com/4SQckvN - "AHHHHHH!" *runs away*
It is all about how the details of function declaration is shown. If you look at the function's template parameters, function parameters, and conditionals separately, I do not think it is any complex at all.
Dec 16 2015
prev sibling parent reply Jon D <jond noreply.com> writes:
On Monday, 14 December 2015 at 19:04:46 UTC, bachmeier wrote:
 Something has to be done with the documentation for Phobos 
 functions that involve ranges and templates.
Many useful ideas in this thread. One I don't recall seeing - a standard way to denote whether a routine is lazy or eager. I'm finding this to be a key piece of information. Many standard library routines document this in the description, but presence and presentation is not very consistent. It'd be nice to have this presented in a standard way for routines operating on ranges. --Jon
Dec 16 2015
parent ZombineDev <valid_email he.re> writes:
On Thursday, 17 December 2015 at 07:19:04 UTC, Jon D wrote:
 On Monday, 14 December 2015 at 19:04:46 UTC, bachmeier wrote:
 Something has to be done with the documentation for Phobos 
 functions that involve ranges and templates.
Many useful ideas in this thread. One I don't recall seeing - a standard way to denote whether a routine is lazy or eager. I'm finding this to be a key piece of information. Many standard library routines document this in the description, but presence and presentation is not very consistent. It'd be nice to have this presented in a standard way for routines operating on ranges. --Jon
Yes this something important that is missing. It is currently up to the documentation of a particular function to explain this. I think originally std.range was supposed to be lazy and std.algorithm - eager, but currently it's not a clear cut. Also in different contexts you may need a lazy version of an eager algorithm and vice-versa.
Dec 16 2015