Skip to content

[TODO] guidelines for contributing PR's, code style guide, guidelines for issues, forum #8271

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

Closed
wants to merge 3 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 118 additions & 0 deletions contributing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# guidelines for contributing PR's, code style guide, guidelines for issues, forum
This document should grow over time. These are just guidelines not hard rules (depending on circumstances).
Rationale should be provided for contentious guidelines.

## git
### use `git rebase` instead of `git merge`
In command line (for person doing PR):
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't care one way or the other, but is this currently one of the guidelines used when contributing? I feel this PR should document the guidelines and best practices that are in place, not invent new ones

Copy link
Collaborator

Choose a reason for hiding this comment

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

To be more clear: I think that imposing all this git trickery will only discourage useful PRs. I think I have seen many PRs that were not rebased or squashed, but were accepted anyway

```
git pull --rebase origin devel
# etc: resolve conflicts
```
In github (for person integrating PR):
use `Rebase and merge` instead of `Squash and merge`:
https://help.github.com/articles/about-pull-request-merges/#rebase-and-merge-your-pull-request-commits

rationale:
* keeps history linear
* makes it practical to use git bisect
* no-one cares when a feature was started being worked on
* makes it a bit harder on committer (he may have to resolve conflicts a bit more often after `git pull --rebase origin devel` than after `git pull origin devel`) but makes it easier for everyone else

There is some debate on rebase vs merge but generally the arguments for `git merge` are that it's simpler to use (less merge conflicts)
see also: https://github.com/nim-lang/Nim/pull/2981

### squashing commits
in a multi-commit PR, trivial commits should be squashed; more complex commits (or commits that deal with individual aspects) should not be squashed
```
git rebase -i $starting_hash^
# etc
```

## github issues
* include `nim --version` and OS information in PR
TODO: we should have a cmd line to get all context we need, eg: `nim --issueContext`, analog to `brew gist-logs`
* make sure to include verbatim relevant parts of error message, to make it easier to search for dedupping

## forum
### forum title should be descriptive
Here are some examples take from https://forum.nim-lang.org/

good:
* Jester v0.3.0 and our first CVE ID
* How to pass module and function name to call in a template (or macro)?

bad:
* "explain this behavior for me"
* "i have some question !?"

## documentation
exported functions should have nimdoc comments (eg with `##`)

## testing

### runnableExamples
* try to use `runnableExamples:` block to make generated docs more illustrative and for testing purposes

### unit tests
* more extensive testing (eg that would be overkill for docs) can be done in `when isMainModule` blocks right below the proc:
Copy link
Member

@GULPF GULPF Jul 12, 2018

Choose a reason for hiding this comment

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

This is not what we do now (currently all additional tests go into a single isMainModule block at the bottom of the file), and IMO it shouldn't change. Typically when you're working on a module you're interested in either the implementation or the tests, not both at the same time. Having to read code that is a 50/50 split of tests and implementation is just painful.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Also, the main thing that should be mentioned in this section is testament and how to use it


```nim
proc absolutePath*(path: string, root = getCurrentDir()): string =
## Returns the absolute path of `path`, rooted at `root` (which must be absolute)
## if `path` is absolute, return it, ignoring `root`
runnableExamples:
doAssert absolutePath("a") == getCurrentDir() / "a"
if isAbsolute(path): path
...

when isMainModule:
doAssertRaises(ValueError): discard absolutePath("a", "b")
doAssert absolutePath("a") == getCurrentDir() / "a"
...
```

### integration tests
TODO

## code
Here's a sample code that can serve as reference:
```nim
proc myStringify(a: int) : string =
## Stringifies ``a``.
##
## On Windows, follows this [spec](https://en.wikipedia.org/wiki/Hidden_file_and_hidden_directory).
Copy link
Member

Choose a reason for hiding this comment

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

Isn't this mixing of .rst syntax (double backticks) and .md syntax (link)? Will this work as intended?

##
## **Warning:** may call ``mod.funName`` depending on ``a``.
runnableExamples:
doAssert foo(0) == "0"
result = $(a)
```
* we use double backticks (bolds text in RST) as ooposed to single backticks (italicizes it)
Copy link
Member

Choose a reason for hiding this comment

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

typo (ooposed)


### prefer `proc` > `template` > `macro` when possible
As general rule of thumb, a `proc` should be preferred over a `template`, and a `template` should be preferred over a `macro` whenever possible (use the simplest tool for the job).

rationale:
* procedures are more hygienic and easier to debug
* procedures are compiled only once (or once per instantiating type for generics), unlike templates and macros which are evaluated at every call site; this can affect compile time performance
* templates and macros don't appear in stackraces, making debugging harder
* at high enough optimization levels, the C/C++ compiler will inline the corresponding proc anyways so shouldn't affect performance

Caveats with templates and macros: `untyped` parameters can prevent method call syntax in some cases, eg `myIter.toSeq` see [docs](https://nim-lang.org/docs/manual.html#templates-limitations-of-the-method-call-syntax)

### prefer `any` or `void` (or even `auto`) over `untyped` for `template` and `macro` output when possible
rationale: early type checking makes it easier to debug errors

### prefer `any` or a explicit or generic type over `untyped` for `template` and `macro` parameters when possible
rationale: early type checking makes it easier to debug errors

### use `void` instead of `typed` for `template` and `macro` output
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think this suggestion is very clear. void means - well, no return type. As such, it can only be used when the template does not return anything, or so I think. If I have, say, template foo(): untyped = 5, I should change that untyped into int, not void

```nim
# don't use that, `typed` as output means something very different from `typed` as parameter
template foo(): typed = discard

# instead use one of these which are synonyms and more readable
template foo(): void = discard
template foo() = discard
```