-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Declarator Docs should be limited in scope #438
Comments
One reason for the existence of declarator docs, is apparently the perceived usefulness of being able to provide external documentation for code with the code itself. In my opinion, internal and external documentation are two very different beasts. And declarator docs make it way too easy to mix the two. Thereby either creating documentation with limited usefulness for the maintainer, or for the user. Or in the worst case for both. |
Another reason for the existence of declarator docs, is that with a refactoring, it would be easier to update the external documentation as well because it is closer to the code. In my opinion, a refactor would probably also require explaining the before and after situation in the user documentation. And this would just add clutter to the code for a maintainer. |
The third reason for the existence of declarator docs, is that it would make it easier for the developer to maintain the internal and external documentation. In my experience, that is NOT true. Personally, I have a mindset for writing user documentation. And one for development. They rarely are active for me at the same time. Sometimes I will write user documentation first, as a sort of design of the features. And sometimes the development starts first, iteratively, without a clear view of the final stage. Once it's getting to a beta stage, would be the first time user documentation would be written. With a different mindset from developing, attempting to look at the code from a user point of view. |
thoughts? @finanalyst @thoughtstream @niner @ab5tract |
This comment was marked as resolved.
This comment was marked as resolved.
Pretty sure a pragma could be devised for that.
What would be the purpose of that? I think that generally the problem is really that variables like |
This comment was marked as resolved.
This comment was marked as resolved.
Way back in the Jurassic, when I designed the original Pod6, So I would have no problem if we removed the entire concept of declarator blocks. However, before we contemplate that step, perhaps it would be useful to know |
I use them for documentation, and also use tools for generating other formats(Markdown for example) from them. An example from one of my modules: |
@lizmat Can you expand on some the implementation hurdles you have been facing? That might help to scope the discussion. For example, if Without having any context, I also wonder whether it could be that this particular piece of RakuDoc doesn't belong in the RakuDoc processing code at all and should rather be part of the "regular" grammar (where we can also add caveats such that most (or even all, if there are circularity issues) of the RakuDoc syntax is unavailable in the "decks" (nice phrasing @raiph!). Tangent: I've always felt like |
@CIAvash thanks for your example! But to me they prove exactly why declarator docs are bad. In the ATTRIBUTES section:
What does the Also, why would a user be interested in how the signature of a method is implemented?
To me, this really feels like documentation for a maintainer, not for a user. |
That's why I mentioned the tools, they have a lot of room for improvement. Tools should extract the important parts of the code.
It probably should link to the documentation of the class, if it is usable by the user. So I think the problem lies in the tools. |
It can be a fuzzy line, to be sure. But considering that, post-RakuAST, the FWIW, most other from-source-generated documentation I've encountered take a fair amount of space for displaying to the user -- for a module's API, this would be a developer -- what arguments a given routhine will take.
It's a publicly accessibly part of the API -- why would it not be relevant to the user? |
The problem with class #= foo
A #= bar
{ #= baz
...
} #= zippo Does the declaration start with In the Raku grammar, only In the legacy grammar these three would all be silently ignored. Now clearly this is an artificial example. But when you realize that parameters and blocks can have declarator docs: sub foo(
Int $a where { $_ > 1 } #= foo
) { } In the Raku grammar, the "foo" is attached to the where My point: the "last declarator" rule is not very transparant. FWIW, the "next declarator" isn't either. #| foo
sub
#| bar
foo(Int $a) { } The "foo" is attached to the sub, the "bar" is attached to the parameter (both in legacy grammar and Raku grammar). Again, this is artificially constructed, but I hope it shows that kind of hoops the grammar needs to jump through to get something because all comments are just whitespace. And you can argue, this is a case of DIHWIDT, but I doubt whether a developer will check whether the documentation they thought they added, is showing up at the right place, or at all. In other words: it is all too magic. |
How can the tool determine whether something is supposed to be usable by the user? Most developers don't put a |
Thank you for clarifying. The current rules do indeed seem way too loosey-goosey for even our project's threshold of implementor-torment :) I doubt we would see any significant regressions in the ecosystem if we scoped
In JavaDoc, they get to add some module-implementor torment by forcing awkward syntax that goes above the routine definition where the signature parameters need to be individually maintained and their types spelled out by hand. It also visually breaks the flow when reading through code. But when it comes to IDE tooltip integration or just plain using the generated HTML documentation to actually work with what the code provides, it's immensely helpful. I think the "decks" are a huge step above this and deliver the same functionality with way less maintenance and visual disruption. |
Probably needs to be done using configs? Maybe one config for the whole document and individual configs if some part of the code needs it. Rustdoc for example uses some configs for hiding documentation and doing other things. More info on Rustdoc |
re: #| get all the whys
sub
#| this form of cruelty will be ignored, worry'd, or sorry'd
why {
{ .WHY } #= why??? ... just use a comment!
for @_;
} This "this form of cruelty will be ignored, worry'd, or sorry'd" attaches to the block of the |
This is a different issue. In a REPL or an IDE, linking from an object to the appropriate documentation, should be a separate project. Putting the docs as declarator docs in the core, would not be a solution. |
I think that is a matter for discussion, rather than a settled fact. EDIT: But it's literally a tangent. Let's not worry about it here or now. |
I'm a bit confused, sorry. My proposals were: A) process "decks" in the grammar differently than other RakuDoc syntax Maybe |
Getting back to @CIAvash's example: What I miss in the current RakuDoc, is a simple way to render the signature of a subroutine or a method without any additional comments. Something like:
that would render to something like (in markdown):
|
@ab5tract sorry, got confused / distracted.
It already does? Because declarator docs can appear at any place in the code where there is whitespace. They can not appear in whitespace inside "docks".
That would severely limit usefulness, especially when documenting CLI arguments in scripts. |
For some reason it seems that you have missed that all of my suggestions are around significantly curtailing the appropriate locations for What I'm proposing for the grammar (and which I appreciate might not be possible) is to not treat these as whitespace. They would specifically be optional captures for routines (
Please re-read my earlier message. In item Also, I don't see how there is any usefulness in any context under your proposal to remove them entirely? |
@ab5tract I assume I missed the meaning of "scoped" here? |
I meant in the sense of narrowing down, in this case meaning "only define the concept/allow the parser to accept in this narrowed conception of |
@ab5tract OK, gotcha now. Maybe a first step could be simpler:
|
Sorry for the delay in responding. Just seen this thread. Working from
phone, so I hope comment correctly attached to thread.
Rather than respond to direct questions, here are some considerations:
- The intimate connection between Rakudoc and code means Rakudoc can only
be handled by Raku and a BEGIN expression may be run. For this reason,
hosts like GitHub and raku.land will not generate HTML on the fly from
RakuDoc.
- RakuDoc V2 explicitly distinguishes between elements for IDEs and
elements for documentation. Decks (using abstract 's term - sorry for
autocorrect) are part of the IDE division. However, RakuDoc also explicitly
states that semantic blocks should be available for other tools, and they
can be 'moved' around (eg. Declared at the beginning of a source but
rendered later.)
- One of the meta aims of RakuDoc IMHO seems to have been to provide a
mechanism to handle many of the suggestions of literate programming. This
implies a close connection between the code and the documentation it
concerns. I have not seen any development of this idea though.
- I have used #= and #| ALOT!!! Since I use Comma and Comma pops up the
explanation of a variable to which #| is attached, I find this quite useful
as I develop a distribution. But that is a use of RakuDoc inside an IDE.
- I find the ability to attach #= to variables inside a sub MAIN very!!!!!
useful. I'll forget the parameters for CLI and they are automatically
available.
- But I am frustrated by the limitations of #| . An important structure for
me is a hash and I use them in config situations. I cannot attach a #| to a
key. I would like to generate some documentation that extracts comments
about keys of a hash, because I comment new keys, but can't remember them
all.
- while =finish has not been mentioned yet, it is also a part of RakuDoc
and is code oriented rather than documentation oriented. I have found
=finish to be useful particularly in tests, where sample input can be
placed.
Some questions.
- Can we separate completely everything inside a =rakudoc block so that it
is available before any bytecode has been generated?
- this will mean that we will have to remove A<> markup from being able to
provide the value of a Raku variable. This is a part of the spec of both
POD6 and RakuDoc V2 but no one has ever used it.
- If a deck is used, then its values are only available after bytecode has
been created, and so would not be available for a renderer.
Please ask questions if this is not clear and I'll respond when I get back
online later today.
Richard
…On Sun, 15 Sept 2024, 15:47 Elizabeth Mattijsen, ***@***.***> wrote:
@ab5tract <https://github.com/ab5tract> OK, gotcha now.
Maybe a first step could be simpler:
1. #| is only allowed at the start of a line
2. #= is only allowed when it it *not* at the start of a line
3. extended forms #|( ... ) and #=( ... ) to be disallowed
—
Reply to this email directly, view it on GitHub
<#438 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AACYZHDQLASHIWFTB2FZE4TZWWMX5AVCNFSM6AAAAABOFKPHUCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDGNJRGYZDGOBUHE>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
There have been a lot of valid and useful points made on both sides of the argument.
Because it occurs to me that Raku already has a mechanism for associating information So, instead of specifying that two particular kinds of comment have special meaning class Magician docs 'Base class for magicians' {
has Int $.level;
has Str @.spells;
}
sub duel docs ('Fight mechanics', 'Magicians only, no mortals') (
Magician $a docs 'The first magician in the duel',
Magician $b docs 'The second magician in the duel',
) {
...
}
my $mage docs 'A magician of level 2 or above';
say Magician.WHY; # OUTPUT: «Base class for magicians»
say &duel.WHY.leading; # OUTPUT: «Fight mechanics»
say &duel.WHY.trailing; # OUTPUT: «Magicians only, no mortals.» And perhaps even a my %config =
'size' docs 'Max size of entry' => 42,
'limit' docs 'Apply limiting' => True,
'rand' docs 'Randomizes lookup' => True,
'etc' docs 'Et cetera' => 'et cetera'; It’s not as convenient to the coder as |
Let's start a wish list of elements that should support Decks.
Questions:
I like this idea. |
@patrickbkr Here's my take on your responses. @lizmat will probably correct me.
We need to develop some terms to make these distinctions better. I am fairly certain I have not been as clear as I should have been |
Agreed.
Agreed.
Agreed.
Agreed.
Agreed.
(Quick shout out to jnthn, nine, ab5tract and probably others that all have poured in work on RakuAST.) This is sadly not true. Even in the new RakuAST compiler bytecode generation and execution can in part already happen during the parse / AST generation phase. The classic example being BEGIN blocks which are compiled and executed by the compiler as soon as the parser sees the end of the block. At that point in time the parser hasn't even looked at the text of the input file following that BEGIN block yet. This might be a little oversimplified, but in principle right. @lizmat Agreed? |
Agreed. |
They can, but they don't have to and they do much less often than with the old frontend. Reason is that RakuAST includes infrastructure for interpreting ASTs directly. We use this to avoid the costly bytecode generation+load for trivial expressions. The most notable exception here is role bodies because they generate a lexical context. But maybe we can find an alternative to that. |
[update after @niner's comment below]
Output in terminal:
commenting out the
UpdateHere is the output as suggested below by @niner:
Commentary: This means that at present |
@finanalyst There's currently a bug in the handling of |
@lizmat That's a relief. I thought I got the code wrong. @patrickbkr When the RakuAST parser/compiler bug is fixed, and assuming that the |
It's not really a bug. It's just that the RakuAST frontend does not support BEGIN time compilation with the old frontend. If you run your example with RAKUDO_RAKUAST=1 you've got a decent chance of it doing what you intend. |
@niner You were right - I've amended my comment above. I hadn't quite understood the difference between
|
I like this idea a lot! This will however be potentially non-trivial to implement. But still better than the current situation. And it will probably break possibly quite a few spectests that depend on the "decks are whitespace" semantics. Should I put this in a pull request and get a vote on that? |
@tbrowder You mean "as whitespace" vs "only at specific locations"? |
@patrickbkr When the RakuAST parser/> compiler bug is fixed, and assuming that the say inside the BEGIN is not executed, would this mean the safety issue is fixed in RakuAST when processing documentation?
Just to clarify: The fact that Raku runs BEGIN blocks during the parse is happening deliberately and is necessary, because it is allowed to modify the parser state in BEGIN.
A good example is the OO::Monitors module, which is adding a new keyword `monitor`. The parser needs to run that modules code for it to recognize the "monitor" keyword. If it wouldn't, the parser could not successfully parse any code using the "monitor" keyword.
|
I think I misunderstood. So the result would be the decl blocks would stay as the user defined them? |
Suppose it is possible to prevent the creation of bytecode, and renderer is given an AST with only rakudoc blocks, then the generation of output - including HTML - depends only on the trusted code that changes blocks into output. This trusted code is not affected by the source program. Does this have a safety concern? |
Consider:
```
use OO::Monitors;
#|Doc
my $var;
monitor M { }
#|Doc2
my $var2;
```
Without running the code in OO::Monitors, the parser can't understand the `monitor M { }` line. The parse will fail and it's not possible to produce the AST.
You can't skip running any code during the parse as running that code is often a necessity for the parser to be able to continue parsing.
So in the above code the parser - working top to bottom - doesn't even reach the `#|Doc2` comment on line 8 as it already fails on line 6.
…On September 22, 2024 11:13:36 PM GMT+02:00, Richard Hainsworth ***@***.***> wrote:
> @patrickbkr
> A good example is the OO::Monitors module, which is adding a new keyword `monitor`
Suppose it is possible to prevent the creation of bytecode, and renderer is given an AST with only rakudoc blocks, then the generation of output - including HTML - depends only on the trusted code that changes blocks into output. This trusted code is not affected by the source program.
Does this have a safety concern?
--
Reply to this email directly or view it on GitHub:
#438 (comment)
You are receiving this because you were mentioned.
Message ID: ***@***.***>
|
I’ve been thinking about how we can make the proposed non-whitespace In looking at the current specification, it seems obvious that the class Base { #= Example 1
...
}
class Der #= Example 2
is Base
{
method action ( #= Example 3
$argie, #= Example 4
$bargie #= Example 5
)
{...}
}
my Int $answer = 42; #= Example 6 Conceptually, what developers want is to be able to document a construct “on the left”. But, syntactically, that sometimes means “immediately after the declarand itself” (as in examples 2 and 5), If we want to support all those locations with the new non-whitespace In contrast, it would be relatively easy to handle the leading #| Example 7
class Base {
...
}
#| Example 8
class Der is Base
{
#| Example 9
method action (
#| Example 10
$argie,
#| Example 11
$bargie
)
{...}
}
#| Example 12
my Int $answer = 42; That seems to already allow virtually all of the current (sane) uses of So, in order to make Which would give us: class Base #= Example 13
{
...
}
class Der #= Example 14
is Base
{
method action #= Example 15
(
$argie #= Example 16
,
$bargie #= Example 17
)
{...}
}
my Int $answer #= Example 18
= 42; That’s not ideal perhaps (example 16 is particularly unappealing, and examples 14 and 18 class Der #=[ Example 19 ] is Base
{
method action (
$argie #=< Example 20 >,
$bargie #=< Example 21 >
)
{...}
}
my Int $answer #=「Example 22」 = 42; Of course, we probably also need to support multiple consecutive documentors in those locations: #| This is the base class
#| for everything in the system
class Base #= I<It really needs
#= a much better name
#= of course>
{...} The only other element we’ve discussed and which that this approach doesn’t handle Personally, I think we should defer adding that until we see how the proposed changes my %preconfig =
#| Max size of entry
size => 42,
#| Apply limiting
limit => True,
#| Randomizes lookup
rand => True,
#| Et cetera
etc => 'et cetera';
my %postconfig =
'size' #=[ Max size of entry ] => 42,
'limit' #=[ Apply limiting ] => True,
'rand' #=[ Randomizes lookup ] => True,
'etc' #=[ Et cetera ] => 'et cetera'; Note that in the case of a trailing documentor for hash keys, the key has to be |
I do like the idea to limit the positions the Decks can appear in. But I think we are stretching the Comparing this latest proposal to the earlier idea to utilize a
I don't like the
bit. But maybe we can come up with a nicer approach to have multiline strings there. |
Docks? Disagree with using/implementing this terminology. Sounds too much like Docs. |
Just a typo on my side. Corrected. |
I like and frequently use declarator blocks in my everyday code. They are great way of communicating with developers. Comparing to regular POD:
BTW: I never liked POD, both in Perl and Raku. When I first encountered Rust approach with
I was amazed how easy and consistent documentation can become across entire ecosystem. Here is example of my module using this concept. No line noise, no special documentation syntax clutter, just pure information. So for me class/method declarator blocks are the way to go and POD can be removed entirely from core and/or moved to some external library. |
I appreciate your point of view, but I love Raku pod (Rakudoc) and find it easy to use (as opposed to Perl pod). I speak as a regular Perl user since 1993 and Raku user since 2015. (Note RakuAST is making Rakudoc even better.) And we have tools to easily convert Rakudoc to other file forms like Markdown, html, and PDF (and other types I don't currently use). Conversely, we also have tools to convert Rakudoc to Markdown, and there are many other non-Raku tools to convert Markdown to some other document form. Finally, Rakudoc has a much richer, and extensible, syntax which enables almost unlimited enhancement and variety of output PDF and html products. |
I'm late to the party but I wanted to say that in general I like Myself, I actually haven't really used the declarator doc features In comparison, in the emacs lisp world, a typical function definition
The Raku equivalent would be something like:
The elisp docstrings, while technically optional, are required by the It's probably significant that in the case of elisp, the syntax makes But that said, while the "docs" syntax might be a good "in addition |
See current definition and the original thoughts.
This issue is written out of frustration of trying to implement a more sensible way of dealing with declarator docs in RakuDoc v2, and trying to implement a sensible "safe" renderer.
Regardless of the implementation effort that has gone into this, and what still needs to go into, I wonder how many developers really like this feature, and what they would think if this feature would be removed by default in 6.e.
The text was updated successfully, but these errors were encountered: