Human unreadable documentation - the ugly seam between simple D and complex D
Idan Arye via Digitalmars-d
digitalmars-d at puremagic.com
Thu Mar 26 12:32:51 PDT 2015
There is a discussion about D vs Go going on in several
threads(yey for multithreading!), and one thread is about an
article by Gary Willoughby that claims that Go is not suitable
for sophisticated
programmers(http://forum.dlang.org/thread/mev7ll$mqr$1@digitalmars.com).
What's interesting about this one is the reddit comments, which
turned into an argument between simple languages that average
programmers can use and complex languages that only the top 1% of
intelligent programmers can use, but they can extract more out of
them.
But the thing is - the world of the top programmers is not really
separate from that of average programmers. Professional
development teams can have a few top programmers and many average
one, all be working on the same project. Open source projects can
have top programmers working on the core while allowing average
programmers to contribute some simple features. Top programmers
can write libraries that can be used by average programmers.
To allow these things, top programmers and average programmers
should be able to work on the same language. Of course, any
language that average programmers can master should be easy for a
top programmer to master - but the thing is, we also want the top
programmer to be able to bring more out of the language, without
limiting them by it's over-simplicity. This will also benefit the
average programmers, since they also improve the quality of the
libraries and modules they are using.
This idea is nothing new, and was mentioned in the main(=biggest)
current D vs Go
thread(http://forum.dlang.org/thread/mdtago$em9$1@digitalmars.com?page=3#post-jeuhtlocousxtezoaqqh:40forum.dlang.org).
What I want to talk about here is the seams. The hurdles that in
practice make this duality harder.
Let's compare it to another duality that D(and many other
languages, mainly modern systems languages) promotes - the
duality between high-level and low-level. Between write-code-fast
and write-fast-code.
The transition between high-level and low-level code in D
consists by a change of the things uses - which language
constructs, which idioms, which functions. But there aren't any
visible seams. You don't need to use FFI or to dynamically load a
library file written in another language or anything like that -
you simply write the high-level parts like you would write
high-level code and the low-level parts like you would write
low-level code, and they just work together.
The duality between high-level D and low-level D is seamless. The
duality between simple D and complex D - not so much.
The seams here exist mainly in understanding how to use complex
code from simple code. Let's take std.algorithm(.*) for example.
The algorithms' implementations there are complex and use
advanced D features, but using them is very simple. Provided, of
course, that you know how to use them(and no - not everything
that you know becomes simple. I know how to solve regular
differential equations, but it's still very complex to do so).
The problem, as Andrei Alexandrescu pointed
out(http://forum.dlang.org/thread/mdtago$em9$1@digitalmars.com?page=6#post-mduv1i:242169:241:40digitalmars.com),
is learning how to use them. Ideally you'd want to be able to
look at a function's signature and learn from that how to use it.
It's name and return type should tell you what it does and it's
argument names and types should tell you what to send to it. The
documentation only there for a more through description and to
warn you about pitfalls and edge cases.
But when it comes to heavily templated functions - understanding
the signature is HARD. It's hard enough for the top programmers
that can handle the complex D features - it's much harder for the
average programmers that could have easily used these functions
if they could just understand the documentation.
Compare it, for example, to Jave. Even if a library doesn't
contain a single documentation comment, the auto-generated
javadoc that contains just the class tree and method signatures
is usually enough to get an idea of what's going where. In D,
unless the author has provided some actual examples, you are
going to have a hard time trying to sort out these complex
templated signatures...
That's quite an hurdle to go though when wanting to use complex
code from simple code(or even from other complex code). That's
the ugly seam I'm talking about.
Now, if you are working on a big project(be it commercial or
open-source), you can find lot's of examples how to use these
complex functions, and that's probably how you'd tackle the
problem. When you are using some library you usually don't have
that luxury - but these libraries usually have the generated ddoc
at their website. Of course - that generated ddoc is full with
complex templated signatures, so that's not very helpful...
So, what can be done? Maybe the ddoc generator, instead of
writing the whole signature as-is, can emit a more human-readable
version of it?
Let's look at the example Andrei mentioned - startsWith. Let's
take a look at the first overloaded signature:
uint startsWith(alias pred = "a == b", Range, Needles...)(Range
doesThisStart, Needles withOneOfThese) if (isInputRange!Range &&
Needles.length > 1 && is(typeof(.startsWith!pred(doesThisStart,
withOneOfThese[0])) : bool) &&
is(typeof(.startsWith!pred(doesThisStart, withOneOfThese[1..$]))
: uint));
Let's break it down and see what the user needs in order to use
the function:
`uint` - the return type. Needed.
`startsWith` - the function name. Needed.
`(alias pred = "a == b",` - a template argument that the user
might want to supply - Needed.
`Range, Needles...)` - template arguments that should usually be
inferable. The function won't work without them, but since the
user doesn't actually supply them - I'll mark them as not needed.
`(Range doesThisStart, Needles withOneOfThese)` - the function's
arguments. Needed.
The rest are constraints that check the template arguments. They
aren't needed when you try to use the function - though they
might be helpful at figuring out why the compiler yells at you
when you use it wrong.
So, if we take only the needed parts, we get this signature:
uint startsWith(alias pred = "a == b")(Range doesThisStart,
Needles withOneOfThese);
Well, doesn't this look much easier to grasp? Of course, it omits
some very critical information. It doesn't tell you what are
`Range` and `Needles` - you can look for these types in the docs
and find nothing. It also doesn't tell you that `Needles` is
variadic.
Well - what's stopping us from adding this information *below*
the signature? What if ddoc would generate something like this:
uint startsWith(alias pred = "a == b")(Range doesThisStart,
Needles... withOneOfThese);
where:
Range is an inferred template argument
Needles is a variadic inferred template argument
isInputRange!Range
Needles.length > 1
is(typeof(.startsWith!pred(doesThisStart, withOneOfThese[0]))
: bool)
is(typeof(.startsWith!pred(doesThisStart,
withOneOfThese[1..$])) : uint)
We've broken the signature into the parts required to use the
function and the parts required to FULLY understand the previous
parts. The motivation is that the second group of parts is also
important, so it needs to be there, but it creates a lot of
unneeded noise so it shouldn't be a direct part of the
signature(at least not in the doc). It's similar to the docs of
other types used in the signature - it's important to have these
docs somewhere accessible, but you don't want to add them in the
middle of the signature because it'll make it unreadable.
This idea, of course, is not a finally cooked proposal yet. We
need a way to tell ddoc which template arguments are supposed to
be inferred(can this always be done automatically?) and the last
two entries in my example are not super-trivial to grok(I can
rewrite them by-hand to make them super-simple - but can ddoc do
it automatically? and how?). The point of this thread is to start
a discussion about making ddoc generate documentations that are
more... well... human readable.
More information about the Digitalmars-d
mailing list