rust-lang / style-team

Home of the Rust style team
Apache License 2.0
454 stars 56 forks source link

Where clauses #38

Closed nrc closed 7 years ago

nrc commented 8 years ago

In functions, structs, enums, traits, impls, etc.

joshtriplett commented 7 years ago

@emk I think the "short" case is the item we talked about longest. I do actually favor the formatting you suggest (putting all three of those on one line).

The conclusion we ended up coming to was that if the constraints are that short or simple, you could put them directly in the generics, which can go on one line if they fit. That works even better now that we use block indentation for arguments and don't try to align them after the open paren; a larger generics block won't push all the arguments off the right margin. Inline simple constraints in the generics; use where clauses for longer or more complex constraints.

U007D commented 7 years ago

So if we had a full indent for where for the cases where it goes onto its own line, what happens in the case of a multiline parameter list and no return type?

IMHO, @jplatte When the where goes on its own line (as per the condition in your question), option #3.

@joshtriplett To keep things simple, I recommend avoiding ) where entirely; ie. when deciding to put it on a new line, actually put where on a new line (with a full indent).

DorianListens commented 7 years ago

I'd also be in favor of always putting where on its own line, with full indent. It's an important keyword, and it's important to separate where clauses from argument lists. I don't like the look of the where clause at the same indentation level as the function it acts upon, that seems like a very odd visual hierarchy mismatch.

QuietMisdreavus commented 7 years ago

I'm currently updating rustdoc to conform to the newer style guidelines and I ran into a fun wrinkle: Type aliases can also have where clauses. Even better, they go between the alias name and the expanded form.

When written inline, a type alias with a where clause looks like this:

type TestAlias<T> where T: Copy = Vec<T>;

With the proposed formatting, it seems like it should be somewhat like this:

type FormattedAlias<T>
where
    T: Copy
= Vec<T>;

Is this considered proper? That = Vec<T> on its own line looks really awkward, but without changing the grammar to move the where clause after the expanded form (is that the right term?), that seems to be the way to go. It doesn't help that type aliases don't check their type constraints, either.

joshtriplett commented 7 years ago

@QuietMisdreavus Interesting. I think I'd ideally write it all on one line without a where clause (type Something<T: Copy> = Vec<T>;). But in the case where you do want a where clause, that doesn't look like reasonable formatting to me. I don't see a better place to put the =, though; having it start a line seems better than hanging it off the same line as the last where clause. (Also, the where clauses should still have trailing commas when they appear on their own lines.)

QuietMisdreavus commented 7 years ago

Right, I didn't want it to hang off of the last condition, for the same reason as people talking about the opening brace earlier in the thread. I'll let it work like that for now. (And my mistake on the commas; I haven't absorbed that one into my personal style so I forgot them when sketching out the example. >_>)

withoutboats commented 7 years ago

Also should mention that the where clauses on type aliases don't do anything right now.

nrc commented 7 years ago

The only alternative I see is indenting all the following lines:

type FormattedAlias<T>
    where
        T: Copy,
    = Vec<T>;

I think @QuietMisdreavus's suggestion fits our rules better, but having everything on the left margin is annoying.

I agree that getting rid of the where clause is better than both.

alteous commented 7 years ago

I think the following style (adapted from @joshtriplett 's post / @withoutboats ' suggestion) is best:

fn foo<'a, T, U>(
    arg0: &'a T,
    arg1: U,
) -> ReturnType
where
    T: Bound,
    U: AnotherBound,
{
    body
}

Rationale

There maybe a few extra newlines than absolutely necessary, but I think this is a very reasonable trade-off for the gains in readability.

Note that if there's only one type parameter then there's no need for the where clause in the first place:

fn foo<T: Bound>(arg0: T) -> ReturnType {
    body
}
joshtriplett commented 7 years ago

We discussed this further in the style meeting, and https://github.com/rust-lang-nursery/fmt-rfcs/issues/38#issuecomment-284576257 is still an accurate summary of the style we've got consensus around.

Regarding type aliases (as raised by @QuietMisdreavus), I don't think we have a complete consensus on those. We'd like to discuss type aliases and the possibility of single-line where clauses in #74. I think we have consensus that at a minimum, there should be an option available for that; we don't, however, have consensus on that being the default.