Skip to content

Comments

update contracts.dd to reflect DIP1009#2339

Merged
wilzbach merged 2 commits intodlang:masterfrom
zachthemystic:patch-1
Jul 17, 2018
Merged

update contracts.dd to reflect DIP1009#2339
wilzbach merged 2 commits intodlang:masterfrom
zachthemystic:patch-1

Conversation

@zachthemystic
Copy link
Contributor

I edited this on github, but then was unable to compile the docs it to check its final appearance in html (See here for why: https://forum.dlang.org/post/azdfcrfqegubikcyntfj@forum.dlang.org ). At any rate, I'm hoping this can be looked at, in particular by @tgehr for accuracy.

Also, the grammar spec is in a different file and still needs to be changed.

@dlang-bot
Copy link
Contributor

Thanks for your pull request and interest in making D better, @zachthemystic! We are looking forward to reviewing it, and you should be hearing from a maintainer soon.
Please verify that your PR follows this checklist:

  • My PR is fully covered with tests (you can see the annotated coverage diff directly on GitHub with CodeCov's browser extension
  • My PR is as minimal as possible (smaller, focused PRs are easier to review than big ones)
  • I have provided a detailed rationale explaining my changes
  • New or modified functions have Ddoc comments (with Params: and Returns:)

Please see CONTRIBUTING.md for more information.


If you have addressed all reviews or aren't sure how to proceed, don't hesitate to ping us with a simple comment.

Bugzilla references

Your PR doesn't reference any Bugzilla issue.

If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog.

@schveiguy
Copy link
Member

The DAutotest builder will show you a preview of how it looks. But it failed to build due to trailing whitespace. I fixed that for you.

@zachthemystic
Copy link
Contributor Author

zachthemystic commented Apr 11, 2018

But it failed to build due to trailing whitespace. I fixed that for you.

Much appreciated.

$(P As of the acceptance of
$(LINK2 https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1009.md, DIP1009),
pre and post contracts can be written either: 1. in expression form, with
syntaxes similar to $(B assert), or 2. as block statements containing arbitrary
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the inline numbers here:

"... can be written either in expression form, with syntaxes similar to $(B assert), or as block statements containing arbitrary code."

The numbers are confusing, especially when each paragraph is numbered.

$(LINK2 https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1009.md, DIP1009),
pre and post contracts can be written either: 1. in expression form, with
syntaxes similar to $(B assert), or 2. as block statements containing arbitrary
code. The expression form is:)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Start a new paragraph for "The expression form is", so a new paragraph number shows up.

or at some point in the block statement. An `out` contract of the
expression form should omit the identifier when testing for anything other than
the return value. In the block statement form, the identifier (along with its
accompanying parentheses) should likewise be omitted if no test requires it.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really verbose. I think the syntax speaks for itself and doesn't need a full description.

Maybe "The optional identifier in either type of out contract is set to the return value of the function." That's pretty much it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll take your word for it. My objection would be that the documentation can also be intended to help beginners understand the intended use of the features. The whole document is written somewhat like that, as opposed to pure technical documentation. But as I said, I'll take your word for it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are lots of places in the spec, where the syntax is not described in english. It's pretty clear to me in the syntax that you can omit the identifier if you don't intend to test it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, you're probably right. It's just that I needed to voice my objection in case there was any merit to it.

statement or expression is allowed in the bodies, but it is important
parameters. If a post contract fails, then there is a bug in the function. In either case,
an `assert` statement within the corresponding `in` or `out` block should throw an
`AssertError`.)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should throw -> will throw

(the former makes it sound like it's something you have to ensure)

@zachthemystic
Copy link
Contributor Author

Okay, I added the grammar changes as well, but I'll need to wait for the DAutoTest to finish to check the html appearance.

@zachthemystic
Copy link
Contributor Author

zachthemystic commented Apr 11, 2018

Uh, the DAutoTest failed for the commits adding the grammar files, but I don't know why.

@schveiguy
Copy link
Member

Wow, the build log is quite an explosion of errors. I'm not sure how to diagnose!

I'm wondering if it's somehow actually testing the grammar to see if it's valid within dmd.

@schveiguy
Copy link
Member

ping @CyberShadow

@zachthemystic
Copy link
Contributor Author

I got as far as realizing that the successful build also spews the errors. It spews about twice as much as the failed build. The failed build ended seemingly arbitrarily when it built LaTex, about halfway through the process.

@CyberShadow
Copy link
Member

Uh oh, you have angered the PDF generator :)

It seems to complain about this line somewhere:

            main(string[] args) { ... }

It's not part of this diff, so it's likely that some bit of syntax went through unescaped in the Latex intermediary file, which in turn caused some tag to not be properly closed (or prematurely closed).

The next step would be to hunt which part of this diff causes the problem, and add escapes as necessary.

I got as far as realizing that the successful build also spews the errors.

Nope, it doesn't - go to the DAutoTest page, click on the link by "Base result", then see the log linked there - there are lots of PDF warnings, but it ultimately succeeds.

$(LINK2 https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1003.md, DIP1003),
the keyword $(D body) was required instead of `do`, and may still be encountered in
old code bases. In the long term, $(D body) may be deprecated, but for now it's allowed both
as a keyword in this context and as an identifier elsewhere (although $(D do) is preferred).) )
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it just me, or there is one more ) here than there should be?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I put the parens around "(Before the acceptance of... elsewhere (although do is preferred).) )"
The last parens are to close the paragraph $(P ...). I'll remove the "although do" set of parens.
This file did pass DAutoTest before the grammar commits, so it's not the cause of the errors.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vim says the parens are legit.

@zachthemystic
Copy link
Contributor Author

go to the DAutoTest page, click on the link by "Base result", then see the log linked there - there are lots of PDF warnings, but it ultimately succeeds.

Yes, it succeeds. The failed build fails about halfway through. Search for "LaTeX Warning: Hyper reference `MAIN' on page" on the successful build, and you'll see it appears halfway through, whereas that's the line that caused the failed build to fail. Baffling! Anyway, I made two tiny edits and now have to wait again on the results.

@wilzbach
Copy link
Contributor

Why don't you build it locally and see where the error is coming from?
Might be a bit faster then waiting..

@zachthemystic
Copy link
Contributor Author

zachthemystic commented Apr 11, 2018

Why don't you build it locally and see where the error is coming from?
Might be a bit faster then waiting..

I couldn't build it. See the first comment in this PR: #2339 (comment)

Also, the error, as it turns out, is in PDF generation, which I would have had to rely on the autotester for anyway.

@zachthemystic
Copy link
Contributor Author

The next step would be to hunt which part of this diff causes the problem, and add escapes as necessary.

This is hard for me, because I couldn't get it to build on my machine, so I was forced to use DAutoTest. The instructions in CONTRIBUTING.md failed when "make -f posix.mak html" errored with:
"...
make[1]: Nothing to be done for `all'.
.generated/stable_dmd-2.078.2/dmd2/osx/bin/dub build --compiler=.generated/stable_dmd-2.078.2/dmd2/osx/bin/dmd --root=ddoc &&
mv ddoc/ddoc_preprocessor .generated/ddoc_preprocessor
Invalid source/import path: /Users/zach/dlang/dmd/src/dmd
Invalid source/import path: /Users/zach/dlang/dmd/generated/dub
Running pre-generate commands for dmd:frontend...
/bin/sh: ./config.sh: No such file or directory
Command failed with exit code 127
make: *** [.generated/ddoc_preprocessor] Error 2"

@zachthemystic
Copy link
Contributor Author

zachthemystic commented Apr 12, 2018

(EDIT: Sorry, shot in the dark. Turns out Ddoc allows nested parens in macros. Now I know...) I remembered seeing something odd, i.e. naked '( )' in the existing class and struct invariant grammars, instead of $(LPAREN) and $(RPAREN). Let's see if that fixes it.

@zachthemystic
Copy link
Contributor Author

zachthemystic commented Apr 12, 2018

It seems to complain about this line somewhere: main(string[] args) { ... }

There is one with int main(... on line 2185 of function.dd. I can't see anything unusual about it though. It's just in a regular code section.

@wilzbach
Copy link
Contributor

This is hard for me, because I couldn't get it to build on my machine, so I was forced to use DAutoTest. The instructions in CONTRIBUTING.md failed when "make -f posix.mak html" errored with:

Should be fixed by #2340

@zachthemystic
Copy link
Contributor Author

Should be fixed by #2340

I could be doing something wrong, but with that pull it still isn't reading the dub.sdl file for me:
"...
make[1]: Nothing to be done for `all'.
.generated/stable_dmd-2.078.2/dmd2/osx/bin/dub build --compiler=.generated/stable_dmd-2.078.2/dmd2/osx/bin/dmd --root=ddoc &&
mv ddoc/ddoc_preprocessor .generated/ddoc_preprocessor
No package file found in /Users/zach/dlang/dmd/, expected one of dub.json/dub.sdl/package.json
make: *** [.generated/ddoc_preprocessor] Error 2"

$(GLINK MissingFunctionBody)

$(GNAME FunctionLiteralBody):
$(GLINK SpecifiedFunctionBody)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The build is failing because of this line.
It gets translated to this

{\fontshape{sl}\selectfont FunctionBody}:
    \textit{SpecifiedFunctionBody}
    \textit{MissingFunctionBody}
\par
{\fontshape{sl}\selectfont FunctionLiteralBody}:
    \textit{SpecifiedFunctionBody}
\par

I don't know why removing these two line works though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for testing. I'm out of my depth on this, I'm afraid.

Copy link
Member

@andralex andralex left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CyberShadow think you can take a look at the LaTeX issue?

@CyberShadow
Copy link
Member

If it's another crazy problem with paging or whatever that causes it to break on a completely innocent-looking spot, then I don't think there's much I can do rather than suggest to drop PDF generation, or switch to a different method to generate it, like rendering+printing HTML in a headless browser.

@wilzbach
Copy link
Contributor

wilzbach commented Jul 3, 2018

I think the failure is related to this #2363 (comment)

Your main error here is using \lstinline in the argument of another command, like most verbatim constructs that does not work. You almost got away with it except in the last case, the page break happens inside a listings block so you end up calling listings recursively inside itself and things go wrong.

https://tex.stackexchange.com/questions/229113/another-extra-or-forgotten-endgroup

However, I don't know how to fix it either. Probably breaking the Grammar sections into individual pieces could help...

Copy link

@ghost ghost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't merge this. In case you didn't see the issue yet : everybody have missed that InExpression existed before DIP 1009 (https://issues.dlang.org/show_bug.cgi?id=19062).

$(GLINK OutStatement)

$(GNAME InExpression):
$(D in $(LPAREN)) $(GLINK2 expression, ContractArguments) $(D $(RPAREN))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InExpression already exists [1].

[1] https://dlang.org/spec/grammar.html#InExpression

@wilzbach
Copy link
Contributor

I think the failure is related to this #2363 (comment)

So this makes it compile:

diff --git a/spec/function.dd b/spec/function.dd
index 685d597e..1b7b10e8 100644
--- a/spec/function.dd
+++ b/spec/function.dd
@@ -52,7 +52,11 @@ $(GNAME InOutX):
     $(D ref)
     $(RELATIVE_LINK2 return-ref-parameters, $(D return ref))
     $(D scope)
+)
+
+$(H4 $(LNAME2 grammar, foo))
 
+$(GRAMMAR
 $(GNAME FunctionAttributes):
     $(GLINK FunctionAttribute)
     $(GLINK FunctionAttribute) $(I FunctionAttributes)

So as mentioned just splitting up the grammar section in multiple pieces...
I pushed a more specific commit that splits the grammar up in multiple parts to your PR. Feel free to modify it, it's just a suggestion.

@zachthemystic
Copy link
Contributor Author

It passes. That is all that matters at this point. Thank you.

Copy link
Contributor

@wilzbach wilzbach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made my pass. @zachthemystic it has 12 commits now. Should we squash them?

contracts validate the result of the statement. The most typical use of this
would be in validating the return value of a function and of any side effects it has.
The syntax is:)
In D, pre contracts begin with `in`, and post contracts begin with `out`. They
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about this, but I would spell them pre-contracts and post-contracts? (Google even suggest precontract)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just copied the style of the previous documentation. It seems subjective, and not a source of confusion.


$(P As of the acceptance of
$(LINK2 https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1009.md, DIP1009),
pre and post contracts can be written either in expression form, with
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure whether we should mention the DIP in the specification as they are supposed to be self-contained.
Hence, I would simply say: "Pre- and post-contracts can be written ..."

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should probably just indicate the first compiler version that incorporates the feature then. ( 2.081.0 )

in(a > 0)
in(b >= 0, "b cannot be negative!")
out(r; r > 0, "return must be positive")
out(; a != 0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW D/Phobos style is to indent on the same level: https://dlang.org/dstyle.html#phobos_declarations

$(P Invariant blocks should contain `assert` expressions, and should throw
`AssertError`s when they fail. As of
$(LINK2 https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1009.md, DIP1009),
invariants can also be written as expression statements, with `assert` implied:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, I'm not sure we should mention the DIP in a specification document that is intended to be read offline.

$(GNAME MissingFunctionBody):
$(D ;)
$(GLINK FunctionContracts)$(OPT) $(GLINK InOutContractExpression) $(D ;)
$(GLINK FunctionContracts)$(OPT) $(GLINK InOutStatement)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't there a semi-colon missing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. The existing grammar is peculiar, and possibly bad design, but it is meant to prevent a semicolon coming after the end brace, };, as in:

int func() in { ... }; // <-- bad, already an error

The way you indicate the body here would be to now say do. Anything else (other than another in or out) means the function body is missing, and the declaration is over, and the parser moves on.

Arguably the no-semicolon-after-brace design is questionable. It hasn't ever mattered much, because currently a contact without a body is only legal in interface declarations, and rarely appears. It could however be expanded to ordinary function declarations eventually, at which point we might see more complaints about it. (e.g. "Why can't I just add the semicolon?")

Anyway, after a parenthesized contract with no body, the expectation would be for the semicolon to be there:

int func() in(...); // <-- legal and expected

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for the extensive explanation.
For the record, I do think this will be confusing for users if contracts are ever allowed for declaration-only functions/structs/classes:

int func() in(...);  // required
int func() in(...); // error

But yeah that's DMD's current behaviour: https://run.dlang.io/is/UwxsE0


$(GNAME FunctionContract):
$(GLINK InOutContractExpression)
$(GLINK InOutStatement)
Copy link
Contributor

@wilzbach wilzbach Jul 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't you group all of them under FunctionContract?

FunctionContract:

  • InContractExpression
  • OutContractExpression
  • InStatement
  • OutStatement

This would also save you two lines above.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There might be a more concise way to write it. The reason they are separate is the need to write do between an In/OutStatement and the function body, whereas there is no need for In/OutExpressions. Timon Gehr wrote it, and he is generally very meticulous, so I left it as is, although I sympathize with the desire to be more concise.

Copy link
Contributor

@wilzbach wilzbach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So a squash and we can finally merge this?

@wilzbach wilzbach dismissed jacob-carlborg’s stale review July 16, 2018 18:46

In/OutExpression ~> In/OutContractExpression

@zachthemystic
Copy link
Contributor Author

One last concern. Maybe we should squash into two commits, with the split being at where the grammar finally passed the pdf generation, for future reference?

@wilzbach
Copy link
Contributor

Good idea.

@zachthemystic
Copy link
Contributor Author

Alright, I don't want my poor git skills to delay it. If you can reduce it to 2 commits do it. It currently pulls the master branch into it as the 2nd to last commit. Sorry about my git skills.

@wilzbach wilzbach force-pushed the patch-1 branch 2 times, most recently from 26193de to 6c5b4f1 Compare July 17, 2018 10:18
@wilzbach
Copy link
Contributor

No worries. Fixed it for you ;-)

@wilzbach wilzbach merged commit a5baf7e into dlang:master Jul 17, 2018
@zachthemystic
Copy link
Contributor Author

Thanks :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants