Skip to content
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

Add style guide #1894

Merged
merged 2 commits into from
Jun 8, 2017
Merged

Add style guide #1894

merged 2 commits into from
Jun 8, 2017

Conversation

Theodus
Copy link
Contributor

@Theodus Theodus commented May 8, 2017

This PR adds a style guide for the standard library and re-formats the standard library code to conform to it.

[skip ci]

@Theodus Theodus added do not merge This PR should not be merged at this time needs discussion during sync labels May 8, 2017
@Theodus
Copy link
Contributor Author

Theodus commented May 8, 2017

This PR should not be merged until we agree about the contents of the style guide and re-format the code.

@Theodus Theodus mentioned this pull request May 8, 2017
Copy link
Member

@jemc jemc left a comment

Choose a reason for hiding this comment

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

Awesome work!

Thanks for taking the time to put this together!

1
2
3
]
Copy link
Member

Choose a reason for hiding this comment

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

I personally disagree about this syntax for multiline arrays - my preferred style is:

 let ns = [as USize:
   1
   2
   3
 ]

However, I think @sylvanc cancels me out on this 🙈

Copy link
Member

Choose a reason for hiding this comment

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

I like @jemc style

Copy link
Contributor

Choose a reason for hiding this comment

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

Me too.

Copy link
Member

Choose a reason for hiding this comment

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

Sylvan likes the opposite of Joe.

Sean doesn't care that much. Sean is good with whatever.
I suggest rock, paper, scissors between Theo and Joe.

Copy link
Contributor

Choose a reason for hiding this comment

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

I really prefer the one in the guide, as it matches other functional languages (F#, OCaml, ML) and the middle one especially (because the brackets line up).

STYLE_GUIDE.md Outdated

// Not OK
{ (a: USize, b: USize): USize => a + b }
```
Copy link
Member

Choose a reason for hiding this comment

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

I think we need to give some guidance on multiline lambdas as well, though I'd be happy to add it as a followup PR if you wanted to go ahead and merge this without that detail.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

More examples for this have been added.

if cond then e1 else e2 end
```

- Match expression cases are __not__ indented.
Copy link
Member

Choose a reason for hiding this comment

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

This can be a bit misleading - it might be read as implying that match expression cases with multiple lines of body should not be indented, and I think we agree that they absolutely should.

We probably need an example showing this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Another example for this has been added.

STYLE_GUIDE.md Outdated
// Not OK
{(a: USize, b: USize): USize =>
a + b
}
Copy link
Member

Choose a reason for hiding this comment

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

Actually, this "Not Ok" example would be my preference, especially when considering lambdas that span many lines.

But I'm curious to hear what @sylvanc thinks, since the recommended "Ok" style here is similar to what @sylvanc prefers for array literals.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Either way, it should be consistent between lambdas, array literals, union types, etc.

Copy link
Member

@jemc jemc May 9, 2017

Choose a reason for hiding this comment

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

I think I disagree about that - I don't think a lambda is in the same category as the other two.

In part because it will be quite common for lambdas to become rather complex by comparison, with other levels of nested indentation. Arrays can technically contain arbitrarily complex blocks of code, but in practice I think any nested levels of indentation would be quite rare. In contrast, nested levels of indentation are quite common in lambdas.

Here's an example of a lambda that isn't really that complex conceptually, but due to the nested levels of indentation, using the "same line" closing bracket strategy would look quite awkward:

rs.next({(p: zmq.SocketPeer, m: zmq.Message)(rs) =>
  if m.size() > 0
    peers = state.peers()
    for peer in peers.values()
      peer.send(recover zmq.Message.>append(m).>push("S") end)
    end
  end
}

Just imagine how it would look with a large match block thrown in.

Copy link
Member

@jemc jemc May 9, 2017

Choose a reason for hiding this comment

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

I'd argue that it's more important for lambda to be stylistically consistent with other constructs that are large blocks of sequential code, like if, while, for, etc.

STYLE_GUIDE.md Outdated
- Blank lines between __one-line__ functions or primitives may be omitted if they are related.

```pony
primitive Red fun apply(): U32 => 0xFF0000FF
Copy link
Member

Choose a reason for hiding this comment

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

unless alignment is part of the spec, i think this example shouldn't have the lining up


### Line Length

The maximum line length is 80 columns.
Copy link
Contributor

Choose a reason for hiding this comment

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

Has there been any discussion of widening this limit to 100 columns? While I understand not letting lines get too wide, 80 always seems so narrow to me. I find 100 to be a sweet spot.

Copy link
Contributor

Choose a reason for hiding this comment

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

Outside of the stdlib, that's fine of course. For the stdlib, 80 works everywhere without line wrapping problems. This is very useful on some displays - and even more often when I want to display two files side by side on a laptop :)

Copy link
Contributor

Choose a reason for hiding this comment

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

I do agree that a modest max column limit makes the code easier to read (less blank area) and easier to compare side by side. But do you really have displays that you use for this that can't show 100x2 columns?

I just wanted to get my 2¢ in before it was too late, but I'll stop whining if no one else prefers 100.

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 use only half of my laptop display for the text editor, so I can usually see about 76 columns without scrolling :)

Copy link
Member

Choose a reason for hiding this comment

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

80! and yes my display does not do 100x2 with the font size i find comfortable.

Copy link
Contributor

Choose a reason for hiding this comment

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

OK, 80 it is. I've given in and always wear my readers when on the computer, which then lets me use a 10pt font on my retina 15" MacBook Pro to get about 300 columns across the screen. But I guess I'm an outlier.


### Blank Lines

- One blank line is placed between top-level declarations such as classes, primitives, actors, etc.
Copy link
Contributor

Choose a reason for hiding this comment

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

I find that having the same one-line gap between functions and classes can cause the classes to get lost a bit. Especially since there is no end on functions and classes.

STYLE_GUIDE.md Outdated
end
```

### Function Declarations
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't this be Function Definitions? Or is that just a C/C++ distinction?

Copy link
Contributor

Choose a reason for hiding this comment

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

Should we also mention that this is for new and be as well?

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe say "method" instead of "function"? We use method to mean new/fun/be, generally. Definition vs declaration is a distinction in many languages (not just C/C++), but not in Pony.

```

- Multiline function parameters are each listed on a separate line. The return type preceded by a `:` is placed at the same indentation level followed by a question mark (if the function is partial). The `=>` is placed on a separate line between the parameter list and the function body at the same indentation level as the `fun` keyword.

Copy link
Contributor

Choose a reason for hiding this comment

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

What about a case where the parameters all fit on one line, but then the return type has to be wrapped? Would something like this be OK?

  fun tag _init(typ': ValueType, default': (Value | None))
    : (ValueType, Value, Bool) ?
  =>
    // ...

Copy link
Contributor

Choose a reason for hiding this comment

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

Good example. That's exactly what I do :)

Copy link
Member

Choose a reason for hiding this comment

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

That is what we do in the sendence code base as well

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Example added

### Whitespace

- Use spaces around binary operators and after commas, colons, and semicolons. Do not put spaces around brackets or parentheses.

Copy link
Contributor

Choose a reason for hiding this comment

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

What about the = used to defined default parameter values?

Copy link
Contributor

Choose a reason for hiding this comment

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

Spaces around those too please :)

Copy link
Member

Choose a reason for hiding this comment

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

Theodus can you update to include that?

Please no force push that will kill off comments early 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.

Example added

@patternspandemic
Copy link
Contributor

Here are a couple areas of the style guide I thought could use some clarification, as I came across styling some code I wrote:

  • Multi-line lambdas with capture lists.
  • Multi-line type declarations with nested type parameters (i.e. JsonObject data)
  • Long match expression cases of the following form. (Here I decided to break after the | and align "string6" under "string1" to group the set, and to not confuse a match | with the or | of the expression.)
match s
| "string1" | "string2" | "string3" | "string4" | "string5" |
  "string6" | "string7" | "string" => Some()
| "other" => Other()
end

Copy link
Contributor

@sylvanc sylvanc left a comment

Choose a reason for hiding this comment

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

This is awesome and @Theodus is awesome.

1
2
3
]
Copy link
Contributor

Choose a reason for hiding this comment

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

I really prefer the one in the guide, as it matches other functional languages (F#, OCaml, ML) and the middle one especially (because the brackets line up).


### Line Length

The maximum line length is 80 columns.
Copy link
Contributor

Choose a reason for hiding this comment

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

Outside of the stdlib, that's fine of course. For the stdlib, 80 works everywhere without line wrapping problems. This is very useful on some displays - and even more often when I want to display two files side by side on a laptop :)

- Fields have no blank lines between them.
- Functions are separated from other members by one line.

```pony
Copy link
Contributor

Choose a reason for hiding this comment

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

These all need indentation :)

### Whitespace

- Use spaces around binary operators and after commas, colons, and semicolons. Do not put spaces around brackets or parentheses.

Copy link
Contributor

Choose a reason for hiding this comment

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

Spaces around those too please :)

STYLE_GUIDE.md Outdated

```pony
if cond1 then e1
elif cond2 then e2
Copy link
Contributor

Choose a reason for hiding this comment

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

elseif

STYLE_GUIDE.md Outdated

if cond1 then
e1
elif cond2 then
Copy link
Contributor

Choose a reason for hiding this comment

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

elseif

STYLE_GUIDE.md Outdated
end
```

### Function Declarations
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe say "method" instead of "function"? We use method to mean new/fun/be, generally. Definition vs declaration is a distinction in many languages (not just C/C++), but not in Pony.

```

- Multiline function parameters are each listed on a separate line. The return type preceded by a `:` is placed at the same indentation level followed by a question mark (if the function is partial). The `=>` is placed on a separate line between the parameter list and the function body at the same indentation level as the `fun` keyword.

Copy link
Contributor

Choose a reason for hiding this comment

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

Good example. That's exactly what I do :)

@sylvanc
Copy link
Contributor

sylvanc commented May 17, 2017

@Theodus this is fantastic. Thank you!

@patternspandemic good call!

krig added a commit to krig/ponyc that referenced this pull request May 24, 2017
Fixes formatting of I32.min_value().

TODO: the u32 and u64 funs in
_format_int.pony could probably be
largely re-unified.

Update formatting to follow style
guide proposal (ponylang#1894).

Fixes: ponylang#1920
offset: USize = 0,
nth: USize = 0,
predicate: {(box->A!, box->A!): Bool} val =
{(l: box->A!, r: box->A!): Bool => l is r })
Copy link
Member

Choose a reason for hiding this comment

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

this wrapping seems very, weird

Copy link
Member

Choose a reason for hiding this comment

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

To me it seems that this is the best way to be consistent with the "hanging" style for assignments with a large right-hand-side. That is, a parameter with a large default value should have the same style as such an assignment.

Copy link
Member

Choose a reason for hiding this comment

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

cant say i disagree with that. it still seems a little weird.

krig added a commit to krig/ponyc that referenced this pull request May 25, 2017
Fixes formatting of I32.min_value().

TODO: the u32 and u64 funs in
_format_int.pony could probably be
largely re-unified.

Update formatting to follow style
guide proposal (ponylang#1894).

Fixes: ponylang#1920
krig added a commit to krig/ponyc that referenced this pull request May 31, 2017
Fixes formatting of I32.min_value().

TODO: the u32 and u64 funs in
_format_int.pony could probably be
largely re-unified.

Update formatting to follow style
guide proposal (ponylang#1894).

Fixes: ponylang#1920
krig added a commit to krig/ponyc that referenced this pull request May 31, 2017
Fixes formatting of I32.min_value(), I16.min_value(),
etc.

TODO: the various type-specific  funs in
_format_int.pony could probably be
largely re-unified.

Update formatting to follow style
guide proposal (ponylang#1894).

Fixes: ponylang#1920
krig added a commit to krig/ponyc that referenced this pull request May 31, 2017
Fixes formatting of I32.min_value(), I16.min_value(),
etc.

TODO: the various type-specific  funs in
_format_int.pony could probably be
largely re-unified.

Update formatting to follow style
guide proposal (ponylang#1894).

Fixes: ponylang#1920
krig added a commit to krig/ponyc that referenced this pull request Jun 1, 2017
Fixes formatting of I32.min_value(), I16.min_value(),
etc.

TODO: the various type-specific  funs in
_format_int.pony could probably be
largely re-unified.

Update formatting to follow style
guide proposal (ponylang#1894).

Fixes: ponylang#1920
krig added a commit to krig/ponyc that referenced this pull request Jun 1, 2017
Fixes formatting of I32.min_value(), I16.min_value(),
etc.

TODO: the various type-specific  funs in
_format_int.pony could probably be
largely re-unified.

Update formatting to follow style
guide proposal (ponylang#1894).

Fixes: ponylang#1920
[skip ci]
Copy link
Member

@jemc jemc left a comment

Choose a reason for hiding this comment

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

As discussed on the sync call, I'm relenting on multiline arrays.

Thanks for tackling this, @Theodus!

@Theodus Theodus removed the do not merge This PR should not be merged at this time label Jun 7, 2017
@Theodus Theodus merged commit 07763fa into ponylang:master Jun 8, 2017
@Theodus Theodus deleted the style-guide branch June 8, 2017 00:46
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.

6 participants