[Review] SE-0081: Move where clause to end of declaration

I think actual keyword “where” provides enough of a delimiter that it won’t be hard to put something before it, and it seems unlikely to me that we would want to add anything after it without some other delimiter. So I’m not too concerned.

Jordan

···

On May 10, 2016, at 14:29, Hooman Mehr via swift-evolution <swift-evolution@swift.org> wrote:

Although handy for now, I am a bit concerned about moving `where` clause to the end of declaration. This reserves and occupies this wide open space at the end of declarations. I think we might find a better use for this space later as the language evolves. Any thoughts?

On May 10, 2016, at 11:51 AM, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hello Swift community,

The review of "SE-0081: Move where clause to end of declaration" begins now and runs through May 16. The proposal is available here:

  https://github.com/apple/swift-evolution/blob/master/proposals/0081-move-where-expression.md

Reviews are an important part of the Swift evolution process. All reviews should be sent to the swift-evolution mailing list at

  https://lists.swift.org/mailman/listinfo/swift-evolution

or, if you would like to keep your feedback private, directly to the review manager.

What goes into a review?

The goal of the review process is to improve the proposal under review through constructive criticism and contribute to the direction of Swift. When writing your review, here are some questions you might want to answer in your review:

  * What is your evaluation of the proposal?
  * Is the problem being addressed significant enough to warrant a change to Swift?
  * Does this proposal fit well with the feel and direction of Swift?
  * If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
  * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

More information about the Swift evolution process is available at

  https://github.com/apple/swift-evolution/blob/master/process.md

Thank you,

-Chris Lattner
Review Manager

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

+1, I like this one a lot.

-Matt

···

On May 10, 2016, at 21:25, David Waite via swift-evolution <swift-evolution@swift.org> wrote:

  https://github.com/apple/swift-evolution/blob/master/proposals/0081-move-where-expression.md

  * What is your evaluation of the proposal?

+1, I like the syntax and think it can clean up some parser ambiguities.

Today, there are several formats using angle brackets:
- a parameter declaration as an ordered dictionary of names to type or type-decensent restrictions (or Any if not specified)
- an argument declaration as an ordered list of concrete types
- an unordered list of required protocol conformances

Eliminating the where clause sometimes available in parameter declarations simplifies understanding the generic syntaxes.

  * Is the problem being addressed significant enough to warrant a change to Swift?

Yes

  * Does this proposal fit well with the feel and direction of Swift?

Yes, although I don’t know how it evaluates against possible future syntax for the generics manifesto feature lists

  * If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
  * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

Followed discussion

-DW
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I’m a +1, however personally I’d prefer this to be optional my constraints aren’t that complex, for example:

  func someMethod<T where T.Element == String>(value:T) { … }

Personally I prefer to keep such simple cases as they are, but would happily use the new ability to move more complex ones (e.g- dealing with Generator.Element and multiple constraints) to the end as proposed.

The example you give isn't actually a legal constraint. (The legal version would be much longer—you'd need to conform `T` to `Sequence` or `Collection` and test `T.Iterator.Element`, or their Swift 2 equivalents.) Can you provide a more realistic example where you think moving the `where` clause to the end of the declaration is overkill? I've generally found that most where clauses are mind-numbingly long.

···

--
Brent Royal-Gordon
Architechies

I notice now that the proposal does define how the change interacts with type declarations, in the grammar section. However, I still see that as an even worse change than in the function case.

Jon Shier

···

On May 14, 2016, at 1:05 AM, Jon Shier <jon@jonshier.com> wrote:

* What is your evaluation of the proposal?

-1

No one has been able to explain how this change improves readability, it just seems like it’s supposed to be self evident. I would argue that it makes the generic definitions less readable by separating declarations and their relevant where clauses. At best this change just moves the already unreadable mass of text elsewhere, where it’s still unreadable. Furthermore, it trades this supposed readability of generic parameters for decreased readability of the actual function signature, since that signature’s now buried between the generic definitions and the where clauses. This is especially bad when declaring a single generic type that can easily fit on a single line, such as:

func something<T: Decodable where T == T.DecodedType>(with something: T) -> String

turns into this, which is less readable to me, as it hides important information between the generic information:

func something<T: Decodable>(with something: T) -> String where T == T.DecodedType

Also, this proposal doesn’t explain how the definitions for generic types would change. Using the proposed grammar would be even worse on types. From:

final class NetworkOperation<T: Decodable where T == T.DecodedType>: Operation,… {

to:

final class NetworkOperation<T: Decodable>: Operation,… where T == T.DecodedType {

The additional conformances types can have make this an especially bad use case for this proposal.

  * Is the problem being addressed significant enough to warrant a change to Swift?

It can be a problem, but I don’t see how this proposal fixes it. Appropriate code styling, whether manual or provided by an IDE, could provide much better readability than this proposal ever could.

  * Does this proposal fit well with the feel and direction of Swift?

Changes proposed for “readability” need to be closely scrutinized, as one programmer’s readable and another’s Perl. I don’t think this proposal meets the high standard this list has tried to set for things to the language.

  * If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

Java and C++’s generics, which are rather different. And despite what they may have intended, I don’t think generics in either language are used as much as in Swift.

  * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

Read the proposal, the thread thus far, and considered my response.

Jon

Oops, StringCollection and IntegerSequence are bad examples, because we’d need to improve existentials before it could apply to those specific examples.

But that’s desperately needed anyway. I’d still recommend ‘Generalised Existentials’ (generics manifesto) + generic typealiases over moving the where clause.

···

On 14 May 2016, at 10:37, Karl Wagner <razielim@gmail.com> wrote:

  * What is your evaluation of the proposal?

-1

* How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

More than a quick reading, but not really “in-depth” study…

* Does this proposal fit well with the feel and direction of Swift?

I don’t really think it does. I don’t remember anything in Swift that went through such a bizarre change just because it looks ugly.

I mean, the where clause isn’t a comment; it’s not documentation. It’s absolutely vital to anybody and everybody who uses anything with one. Really, I can’t see any logic to splitting the parameter name and constraints. It’s completely baffling, and if it wasn’t that they’re “ugly” I don’t think anybody would give this proposal a second thought. Besides, when I need to look up which parameters I need for a type, it’s nice to have them all in one place in a clearly delimited section of the declaration.

* Is the problem being addressed significant enough to warrant a change to Swift?
* If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

I’m with Jon Shier on this - it is a problem, but it’s one inherent to generics. In some languages, you have great big whoppers for type parameters and have to pass them around everywhere you go; we’re relatively clean with Swift. Nobody writing swift should complain about our type parameters being too messy:

interface Feeder<F extends Food, A extends Animal<F,?>, S extends Store<F>> {
public void buyFoodAndFeed(A animal, S store);
}
class StoreFeeder implements Feeder<Grass, Animal<Grass, ?>, Store<Grass>> {
public void buyFoodAndFeed(Animal<Grass, ?> animal, Store<Grass> store) {
   animal.eat(store.buyFood());
}
}

I have a counter-proposal to tackle the readability issue: that we extend SE-0048: Generic Typealiases [1] to include where clauses. The proposal already mentions this, and simply says "If there is a compelling reason to add this, we can consider extending the model to support them in the future, based on the merits of those reasons.” If we did that, we could drastically shorten function/class declarations - using, say, “StringCollection” or “IntegerSequence” rather than <C:Collection where C.Iterator.Element==String>.

[1](https://github.com/apple/swift-evolution/blob/master/proposals/0048-generic-typealias.md\)

On 10 May 2016, at 20:51, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

Hello Swift community,

The review of "SE-0081: Move where clause to end of declaration" begins now and runs through May 16. The proposal is available here:

  https://github.com/apple/swift-evolution/blob/master/proposals/0081-move-where-expression.md

Reviews are an important part of the Swift evolution process. All reviews should be sent to the swift-evolution mailing list at

  https://lists.swift.org/mailman/listinfo/swift-evolution

or, if you would like to keep your feedback private, directly to the review manager.

What goes into a review?

The goal of the review process is to improve the proposal under review through constructive criticism and contribute to the direction of Swift. When writing your review, here are some questions you might want to answer in your review:

More information about the Swift evolution process is available at

  https://github.com/apple/swift-evolution/blob/master/process.md

Thank you,

-Chris Lattner
Review Manager

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

This is partly an issue of how you use the feature rather than an issue with the feature itself, as you’re assuming that everything is all on one line, but really I think the intent of this feature is to better support multi-line declarations. It enables things like:

  func someMethod<S:SequenceType, T>(value:S) -> AnySequence<T>
    where S.Generator.Element == T { … }

The actual function signature stays on the top, but the constraint can now move down neatly, since it’s a supplementary condition that you may not to consider right away, or at all, if it’s just reinforcing some kind of common-sense limitation.

This is partly why I’d prefer to see it optional though, as some things will fit on one line reasonably well (you probably could with the above for example), but like you say, with it all on one line the return type becomes less visible.

···

On 14 May 2016, at 16:52, Tony Allevato via swift-evolution <swift-evolution@swift.org> wrote:

To me, this makes declarations with complex sets of constraints much harder to read, because I have to hunt them down instead of finding them all in one place. Under this proposal, the longer an argument list gets, the further separated the constraints are from the type parameters that use them.

Hello Swift community,
The review of "SE-0081: Move where clause to end of declaration" begins now and runs through May 16. The proposal is available here:
https://github.com/apple/swift-evolution/blob/master/proposals/0081-move-where-expression.md Reviews are an important part of the Swift evolution process. All reviews should be sent to the swift-evolution mailing list at
  https://lists.swift.org/mailman/listinfo/swift-evolution
or, if you would like to keep your feedback private, directly to the review manager.
What goes into a review?
The goal of the review process is to improve the proposal under review through constructive criticism and contribute to the direction of Swift. When writing your review, here are some questions you might want to answer in your review:
  * What is your evaluation of the proposal?

-1. My thoughts essentially mirror those of Jon Shier, Karl Wagner, and Nicola Salmoria.

To me, this makes declarations with complex sets of constraints much harder to read, because I have to hunt them down instead of finding them all in one place. Under this proposal, the longer an argument list gets, the further separated the constraints are from the type parameters that use them.

This solution also obfuscates function definitions. Having the function's return type be the very last thing in the header line is has very nice readability benefit, and this proposal takes that away by sandwiching the return type awkwardly in the middle.

IMO the readability is improved because the where clause can be easily placed in a new line. Generic function definitions with where clauses typically are too long for being crammed into one line without having the readability suffer. The proposal allows a much more readable splitting of the definition into several lines. This completely alleviates the problem of separating generic type information or sandwiching the return type, because the where clause in the next line will be near the generic type parameter list again.
Taking Jon Shier’s example:
The following definition is already too long IMO. The current syntax does not allow nice splitting of the line and readability suffers from the long gap between the function name and its parameter list:
    func something<T: Decodable where T == T.DecodedType>(with something: T) -> String

instead of writing a long line with sandwiching problems like that:
    func something<T: Decodable>(with something: T) -> String where T == T.DecodedType

I would write:
    func something<T: Decodable>(with something: T) -> String
        where T == T.DecodedType

To recap: I think that readability improves with the proposal for the following reasons:
- The gap between the function name and its parameter list is reduced
- Definitions with where clauses typically are already too long to readably fit into one line, so they should be split over more than one line. The current syntax does not offer a natural position for a line break (breaking before the where even further increases the gap between the function name and its parameter list and it looks ugly because of the angle brackets being on separate lines.

-Thorsten

···

Am 14.05.2016 um 17:52 schrieb Tony Allevato via swift-evolution <swift-evolution@swift.org>:
On 2016-05-10 18:51:29 +0000, Chris Lattner via swift-evolution said:

The admission that some constraints should be allowed inside the angle brackets (conformance constraints) while moving others (associated type constraints) out introduces inconsistency in the language and seems like an incomplete fix. From a teaching point of view, I would find it more difficult to explain to users of the language "constraints that look like *this* go here, but constraints that look like *that* go way over there". The current model of "all generic constraints go between < and >" is clean and simple.

Lastly, from a bit of a pedantic point of view, moving the where-clause to the end of a function declaration makes it look like the function is satisfying some constraints, when it's actually the generic type parameters that are satisfying them. In that sense, it's better to keep them closer together.

  * Is the problem being addressed significant enough to warrant a change to Swift?

Yes, but not in this fashion. I agree with some of the other sentiment that there should be better ways of satisfying complex constraint sets (through generic typealiases or something else) to clean them up, but moving the where-clause creates more readability problems than it solves.

  * Does this proposal fit well with the feel and direction of Swift?

I don't believe so; it adds inconsistency rather than removes it.

  * If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

No languages that allow generics to be expressed so richly as Swift's.

  * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

Read the proposal and followed the mailing list threads.

More information about the Swift evolution process is available at
  https://github.com/apple/swift-evolution/blob/master/process.md
Thank you,
-Chris Lattner
Review Manager
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I tend to agree with Jon Shier, Karl Wagner, Nicola Salmoria, and Tony Allevato. I think moving `where` to the end hinders comprehension. The extra constraint abilities that Nicola brought up look interesting.

···

On 15 May 2016, at 1:52 AM, Tony Allevato via swift-evolution <swift-evolution@swift.org> wrote:

On 2016-05-10 18:51:29 +0000, Chris Lattner via swift-evolution said:

Hello Swift community,
The review of "SE-0081: Move where clause to end of declaration" begins now and runs through May 16. The proposal is available here:
https://github.com/apple/swift-evolution/blob/master/proposals/0081-move-where-expression.md Reviews are an important part of the Swift evolution process. All reviews should be sent to the swift-evolution mailing list at
  https://lists.swift.org/mailman/listinfo/swift-evolution
or, if you would like to keep your feedback private, directly to the review manager.
What goes into a review?
The goal of the review process is to improve the proposal under review through constructive criticism and contribute to the direction of Swift. When writing your review, here are some questions you might want to answer in your review:
  * What is your evaluation of the proposal?

-1. My thoughts essentially mirror those of Jon Shier, Karl Wagner, and Nicola Salmoria.

To me, this makes declarations with complex sets of constraints much harder to read, because I have to hunt them down instead of finding them all in one place. Under this proposal, the longer an argument list gets, the further separated the constraints are from the type parameters that use them.

This solution also obfuscates function definitions. Having the function's return type be the very last thing in the header line is has very nice readability benefit, and this proposal takes that away by sandwiching the return type awkwardly in the middle.

The admission that some constraints should be allowed inside the angle brackets (conformance constraints) while moving others (associated type constraints) out introduces inconsistency in the language and seems like an incomplete fix. From a teaching point of view, I would find it more difficult to explain to users of the language "constraints that look like *this* go here, but constraints that look like *that* go way over there". The current model of "all generic constraints go between < and >" is clean and simple.

Lastly, from a bit of a pedantic point of view, moving the where-clause to the end of a function declaration makes it look like the function is satisfying some constraints, when it's actually the generic type parameters that are satisfying them. In that sense, it's better to keep them closer together.

  * Is the problem being addressed significant enough to warrant a change to Swift?

Yes, but not in this fashion. I agree with some of the other sentiment that there should be better ways of satisfying complex constraint sets (through generic typealiases or something else) to clean them up, but moving the where-clause creates more readability problems than it solves.

  * Does this proposal fit well with the feel and direction of Swift?

I don't believe so; it adds inconsistency rather than removes it.

  * If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

No languages that allow generics to be expressed so richly as Swift's.

  * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

Read the proposal and followed the mailing list threads.

More information about the Swift evolution process is available at
  https://github.com/apple/swift-evolution/blob/master/process.md
Thank you,
-Chris Lattner
Review Manager
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I think actual keyword “where” provides enough of a delimiter that it won’t be hard to put something before it, and it seems unlikely to me that we would want to add anything after it without some other delimiter. So I’m not too concerned.

Yeah, that’s my feeling as well.

  - Doug

···

On May 10, 2016, at 3:46 PM, Jordan Rose via swift-evolution <swift-evolution@swift.org> wrote:

Jordan

On May 10, 2016, at 14:29, Hooman Mehr via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Although handy for now, I am a bit concerned about moving `where` clause to the end of declaration. This reserves and occupies this wide open space at the end of declarations. I think we might find a better use for this space later as the language evolves. Any thoughts?

On May 10, 2016, at 11:51 AM, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hello Swift community,

The review of "SE-0081: Move where clause to end of declaration" begins now and runs through May 16. The proposal is available here:

  https://github.com/apple/swift-evolution/blob/master/proposals/0081-move-where-expression.md

Reviews are an important part of the Swift evolution process. All reviews should be sent to the swift-evolution mailing list at

  https://lists.swift.org/mailman/listinfo/swift-evolution

or, if you would like to keep your feedback private, directly to the review manager.

What goes into a review?

The goal of the review process is to improve the proposal under review through constructive criticism and contribute to the direction of Swift. When writing your review, here are some questions you might want to answer in your review:

  * What is your evaluation of the proposal?
  * Is the problem being addressed significant enough to warrant a change to Swift?
  * Does this proposal fit well with the feel and direction of Swift?
  * If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
  * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

More information about the Swift evolution process is available at

  https://github.com/apple/swift-evolution/blob/master/process.md

Thank you,

-Chris Lattner
Review Manager

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

To me, this makes declarations with complex sets of constraints much harder to read, because I have to hunt them down instead of finding them all in one place. Under this proposal, the longer an argument list gets, the further separated the constraints are from the type parameters that use them.

This is partly an issue of how you use the feature rather than an issue with the feature itself, as you’re assuming that everything is all on one line, but really I think the intent of this feature is to better support multi-line declarations. It enables things like:

  func someMethod<S:SequenceType, T>(value:S) -> AnySequence<T>
    where S.Generator.Element == T { … }

I'm not assuming that. Under the current syntax, I would format your example as:

    func someMethod<
        S: SequenceType, T
        where S.Generator.Element == T
    >(value: S) -> AnySequence<T> {
        ...
    }

which I find to be quite readable across multiple lines without scattering the generic type information in two places across the function.

The actual function signature stays on the top, but the constraint can now move down neatly, since it’s a supplementary condition that you may not to consider right away, or at all, if it’s just reinforcing some kind of common-sense limitation.

That's kind of a judgment call, though. Not all constraints fit that mold—some encode very important information that it makes sense to keep up front.

This is partly why I’d prefer to see it optional though, as some things will fit on one line reasonably well (you probably could with the above for example), but like you say, with it all on one line the return type becomes less visible.

No matter how you format the proposed syntax, the return type is sandwiched in the middle of two things that describe generic type information—whether it's on one line or not doesn't change that. I believe that harms readability, especially if you have some constraints (conformance) on the left and some (associated types) on the right.

I would be strongly opposed to making this optional—that adds complexity to the language to support parsing two patterns, as well as the cognitive load of someone reading Swift code, especially if written in the different style. As was mentioned in another thread, "Swift is an opinionated languge", and I hope we'd be prescriptive about syntactic constructs like this that are more significant than "does the curly brace go on the same line or the next line". (Even if the choice is one that I disagree with in the end, I'd rather there be one way than multiple ways!)

···

On 2016-05-14 16:29:40 +0000, Haravikk via swift-evolution said:

On 14 May 2016, at 16:52, Tony Allevato via swift-evolution > <swift-evolution@swift.org> wrote:

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Tony & Haravikk,

(Reformatting your quoted examples just a bit…)

It enables things like:
    func someMethod<S : SequenceType, T>(value: S) -> AnySequence<T>
        where S.Generator.Element == T { ... }

I'm not assuming that. Under the current syntax, I would format your example as:

    func someMethod<
        S : SequenceType, T
        where S.Generator.Element == T
    >(value: S) -> AnySequence<T> {
        ...
    }

You are both right here, but please note that the proposal still also allows moving all constraints to the `where` clause:

    func someMethod<S, T>(value: S) -> AnySequence<T>
        where S : SequenceType,
              S.Generator.Element == T
    {
        ...
    }

just like Swift 2 allows doing so within the `<...>` brackets:

    func someMethod<S, T
        where S : SequenceType, S.Generator.Element == T
    >(value: S) -> AnySequence<T> {
        ...
    }

The reason I'd recommend that style for anything but simple constraints is because:

1) It makes the call site `let items = someMethod(value: things)` lightest to visually match to the declaration, because the only thing between the function name and its argument list is the `<...>` bracketed list of introduced generic types which you'll expect to see in the function signature and constraints.

2) In general, the `where` constraints really apply to the whole function/type declaration, not just a single generic parameter.

3) It was claimed that all constraints should go right next to the introduction of the generic parameters. But that isn't the whole case because Swift also applies implicit constraints onto any generic parameters that are used in constrained positions. If that wasn't clearly said, take the following example in Swift 2.x:

    func aMethod<S : SequenceType, T where S.Generator.Element == T>(value: S) -> Set<T> {
        return Set(value)
    }

That declaration actually makes you wait all the way until the return type `Set<T>` until you learn that `T` must also necessarily be `Hashable`. So I don't see how it's that different if the `where` clause isn't right next to the generic type arguments' introduction:

    func aMethod<S, T>(value: S) -> Set<T> // FWIW, this line contains what I usually have in mind when browsing code.
        where // T : Hashable, // (implicit)
              S : SequenceType,
              S.Generator.Element == T
    {
        return Set(value)
    }

— Pyry

PS. Besides, neither the original example nor mine was really fair; you don't need `where` for these. Instead, you'd just write:

    func someMethod<S : SequenceType>(value: S) -> AnySequence<S.Generator.Element> {
        ...
    }

which SE-0081 has nothing to argue for or against.

To me, this makes declarations with complex sets of constraints much harder to read, because I have to hunt them down instead of finding them all in one place. Under this proposal, the longer an argument list gets, the further separated the constraints are from the type parameters that use them.

This is partly an issue of how you use the feature rather than an issue with the feature itself, as you’re assuming that everything is all on one line, but really I think the intent of this feature is to better support multi-line declarations. It enables things like:
  func someMethod<S:SequenceType, T>(value:S) -> AnySequence<T>
    where S.Generator.Element == T { … }

I'm not assuming that. Under the current syntax, I would format your example as:

  func someMethod<
      S: SequenceType, T
      where S.Generator.Element == T
  >(value: S) -> AnySequence<T> {
      ...
  }

which I find to be quite readable across multiple lines without scattering the generic type information in two places across the function.

But this scatters the function definition itself, i.e. the name of the function and its parameter list and return type over multiple lines.
And splitting the <> over multiple lines is really ugly. The leading > even looks like an operator (is it func >(value: S) being defined?).

I think

func someMethod<S: SequenceType, T>(value: S) -> AnySequence<T>
  where S.Generator.Element == T {
  …
}

is much more readable.

Or what about using some more suggestive names for the generic paramters, so that the core of the function definition can be kept even shorter without loosing readability:

func someMethod<Seq, Elem>(value: Seq) -> AnySequence<Elem>
  where
  Seq: SequenceType,
  Seq.Generator.Element == Elem {
  …
}

Here, I don’t see the need to keep all constraints up front because the generic parameters already suggest their nature. The where clause just fills in the technical constraints.

This would not be possible with the current syntax at all.

-Thorsten

···

Am 14.05.2016 um 20:19 schrieb Tony Allevato via swift-evolution <swift-evolution@swift.org>:
On 2016-05-14 16:29:40 +0000, Haravikk via swift-evolution said:

On 14 May 2016, at 16:52, Tony Allevato via swift-evolution <swift-evolution@swift.org> wrote:

The actual function signature stays on the top, but the constraint can now move down neatly, since it’s a supplementary condition that you may not to consider right away, or at all, if it’s just reinforcing some kind of common-sense limitation.

That's kind of a judgment call, though. Not all constraints fit that mold—some encode very important information that it makes sense to keep up front.

This is partly why I’d prefer to see it optional though, as some things will fit on one line reasonably well (you probably could with the above for example), but like you say, with it all on one line the return type becomes less visible.

No matter how you format the proposed syntax, the return type is sandwiched in the middle of two things that describe generic type information—whether it's on one line or not doesn't change that. I believe that harms readability, especially if you have some constraints (conformance) on the left and some (associated types) on the right.

I would be strongly opposed to making this optional—that adds complexity to the language to support parsing two patterns, as well as the cognitive load of someone reading Swift code, especially if written in the different style. As was mentioned in another thread, "Swift is an opinionated languge", and I hope we'd be prescriptive about syntactic constructs like this that are more significant than "does the curly brace go on the same line or the next line". (Even if the choice is one that I disagree with in the end, I'd rather there be one way than multiple ways!)

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

One conceivable use of `where` that this would shut the door on: infix `where` for generalized existentials, e.g. `Protocol where AssociatedType == Int` could be the Protocol existential with Self.AssociatedType constrained to Int.

-Joe

···

On May 10, 2016, at 4:19 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

On May 10, 2016, at 3:46 PM, Jordan Rose via swift-evolution <swift-evolution@swift.org> wrote:

I think actual keyword “where” provides enough of a delimiter that it won’t be hard to put something before it, and it seems unlikely to me that we would want to add anything after it without some other delimiter. So I’m not too concerned.

Yeah, that’s my feeling as well.

** What is your evaluation of the proposal?*
A novelty idea

** Is the problem being addressed significant enough to warrant a change to
Swift?*
Some programmers love compact code and make Swift no difference to other
languages, change is indeed easier and almost no barrier for all level of
readers.

** Does this proposal fit well with the feel and direction of Swift?*
It makes presentation slide and teaching readability and avoid information
overload when dealing large scale projects.

** If you have used other languages or libraries with a similar feature,
how do you feel that this proposal compares to those?*
NIL

** How much effort did you put into your review? A glance, a quick reading,
or an in-depth study?*
A glance at the code,

···

On Wed, May 11, 2016 at 7:19 AM, Douglas Gregor via swift-evolution < swift-evolution@swift.org> wrote:

On May 10, 2016, at 3:46 PM, Jordan Rose via swift-evolution < > swift-evolution@swift.org> wrote:

I think actual keyword “where” provides enough of a delimiter that it
won’t be hard to put something before it, and it seems unlikely to me that
we would want to add anything *after* it without some *other* delimiter.
So I’m not too concerned.

Yeah, that’s my feeling as well.

- Doug

Jordan

On May 10, 2016, at 14:29, Hooman Mehr via swift-evolution < > swift-evolution@swift.org> wrote:

Although handy for now, I am a bit concerned about moving `where` clause
to the end of declaration. This reserves and occupies this wide open space
at the end of declarations. I think we might find a better use for this
space later as the language evolves. Any thoughts?

On May 10, 2016, at 11:51 AM, Chris Lattner via swift-evolution < > swift-evolution@swift.org> wrote:

Hello Swift community,

The review of "SE-0081: Move where clause to end of declaration" begins
now and runs through May 16. The proposal is available here:

https://github.com/apple/swift-evolution/blob/master/proposals/0081-move-where-expression.md

Reviews are an important part of the Swift evolution process. All reviews
should be sent to the swift-evolution mailing list at

https://lists.swift.org/mailman/listinfo/swift-evolution

or, if you would like to keep your feedback private, directly to the
review manager.

What goes into a review?

The goal of the review process is to improve the proposal under review
through constructive criticism and contribute to the direction of Swift.
When writing your review, here are some questions you might want to answer
in your review:

* What is your evaluation of the proposal?
* Is the problem being addressed significant enough to warrant a change to
Swift?
* Does this proposal fit well with the feel and direction of Swift?
* If you have used other languages or libraries with a similar feature,
how do you feel that this proposal compares to those?
* How much effort did you put into your review? A glance, a quick reading,
or an in-depth study?

More information about the Swift evolution process is available at

https://github.com/apple/swift-evolution/blob/master/process.md

Thank you,

-Chris Lattner
Review Manager

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Tony & Haravikk,

(Reformatting your quoted examples just a bit…)

It enables things like:
    func someMethod<S : SequenceType, T>(value: S) -> AnySequence<T>
        where S.Generator.Element == T { ... }

I'm not assuming that. Under the current syntax, I would format your example as:

    func someMethod<
        S : SequenceType, T
        where S.Generator.Element == T
    >(value: S) -> AnySequence<T> {
        ...
    }

You are both right here, but please note that the proposal still also allows moving all constraints to the `where` clause:

    func someMethod<S, T>(value: S) -> AnySequence<T>
        where S : SequenceType,
              S.Generator.Element == T
    {
        ...
    }

just like Swift 2 allows doing so within the `<...>` brackets:

    func someMethod<S, T
        where S : SequenceType, S.Generator.Element == T
    >(value: S) -> AnySequence<T> {
        ...
    }

The reason I'd recommend that style for anything but simple constraints is because:

1) It makes the call site `let items = someMethod(value: things)` lightest to visually match to the declaration, because the only thing between the function name and its argument list is the `<...>` bracketed list of introduced generic types which you'll expect to see in the function signature and constraints.

2) In general, the `where` constraints really apply to the whole function/type declaration, not just a single generic parameter.

3) It was claimed that all constraints should go right next to the introduction of the generic parameters. But that isn't the whole case because Swift also applies implicit constraints onto any generic parameters that are used in constrained positions. If that wasn't clearly said, take the following example in Swift 2.x:

    func aMethod<S : SequenceType, T where S.Generator.Element == T>(value: S) -> Set<T> {
        return Set(value)
    }

That declaration actually makes you wait all the way until the return type `Set<T>` until you learn that `T` must also necessarily be `Hashable`. So I don't see how it's that different if the `where` clause isn't right next to the generic type arguments' introduction:

    func aMethod<S, T>(value: S) -> Set<T> // FWIW, this line contains what I usually have in mind when browsing code.
        where // T : Hashable, // (implicit)
              S : SequenceType,
              S.Generator.Element == T
    {
        return Set(value)
    }

— Pyry

IMHO proposals like this should never be discussed in the context of trivial examples as the full scope of their value gets lost. I have written enough generics code in other languages to appreciate the idea of a 'headline-form-followed-by-the-details-idea' for any complex declaration. My understanding is that the proposal offers to make us write explicitely what anyone reading the code will try to extract out of the declaration. Instead of 100's or 1000's doing the work in their heads, the code author does it once for all subsequent readers. What's not to like about this idea?

···

On May 14, 2016, at 9:43 PM, Pyry Jahkola via swift-evolution <swift-evolution@swift.org> wrote:

PS. Besides, neither the original example nor mine was really fair; you don't need `where` for these. Instead, you'd just write:

    func someMethod<S : SequenceType>(value: S) -> AnySequence<S.Generator.Element> {
        ...
    }

which SE-0081 has nothing to argue for or against.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

My only reservation would be the choice of WHERE which I would have kept for more *dynamic* situations int the language. My first choice for this would have been WITH which in my minds carries a more permanent, intemporal connotation in my mind. But that is off topic for this discussion.

···

On May 14, 2016, at 9:43 PM, Pyry Jahkola via swift-evolution <swift-evolution@swift.org> wrote:

Tony & Haravikk,

(Reformatting your quoted examples just a bit…)

It enables things like:
    func someMethod<S : SequenceType, T>(value: S) -> AnySequence<T>
        where S.Generator.Element == T { ... }

I'm not assuming that. Under the current syntax, I would format your example as:

    func someMethod<
        S : SequenceType, T
        where S.Generator.Element == T
    >(value: S) -> AnySequence<T> {
        ...
    }

You are both right here, but please note that the proposal still also allows moving all constraints to the `where` clause:

    func someMethod<S, T>(value: S) -> AnySequence<T>
        where S : SequenceType,
              S.Generator.Element == T
    {
        ...
    }

just like Swift 2 allows doing so within the `<...>` brackets:

    func someMethod<S, T
        where S : SequenceType, S.Generator.Element == T
    >(value: S) -> AnySequence<T> {
        ...
    }

The reason I'd recommend that style for anything but simple constraints is because:

1) It makes the call site `let items = someMethod(value: things)` lightest to visually match to the declaration, because the only thing between the function name and its argument list is the `<...>` bracketed list of introduced generic types which you'll expect to see in the function signature and constraints.

2) In general, the `where` constraints really apply to the whole function/type declaration, not just a single generic parameter.

3) It was claimed that all constraints should go right next to the introduction of the generic parameters. But that isn't the whole case because Swift also applies implicit constraints onto any generic parameters that are used in constrained positions. If that wasn't clearly said, take the following example in Swift 2.x:

    func aMethod<S : SequenceType, T where S.Generator.Element == T>(value: S) -> Set<T> {
        return Set(value)
    }

That declaration actually makes you wait all the way until the return type `Set<T>` until you learn that `T` must also necessarily be `Hashable`. So I don't see how it's that different if the `where` clause isn't right next to the generic type arguments' introduction:

    func aMethod<S, T>(value: S) -> Set<T> // FWIW, this line contains what I usually have in mind when browsing code.
        where // T : Hashable, // (implicit)
              S : SequenceType,
              S.Generator.Element == T
    {
        return Set(value)
    }

— Pyry

PS. Besides, neither the original example nor mine was really fair; you don't need `where` for these. Instead, you'd just write:

    func someMethod<S : SequenceType>(value: S) -> AnySequence<S.Generator.Element> {
        ...
    }

which SE-0081 has nothing to argue for or against.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

IMHO proposals like this should never be discussed in the context of trivial examples as the full scope of their value gets lost. I have written enough generics code in other languages to appreciate the idea of a 'headline-form-followed-by-the-details-idea' for any complex declaration. My understanding is that the proposal offers to make us write explicitely what anyone reading the code will try to extract out of the declaration. Instead of 100's or 1000's doing the work in their heads, the code author does it once for all subsequent readers. What's not to like about this idea?

There is a lot not to like about the idea; even if it was optional. Personally, I feel the problem is solved in a much, much more elegant manner by other proposals.

Firstly, the stuff after the ‘where’ clause is getting shorter once typealiases come to protocols. C.Iterator.Element become C.Element. In this one example, that’s 18 characters down to 9 - a 50% reduction in length. We tend to use quite expressive names for associated types, so I expect we’ll see similar gains elsewhere from this very simple proposal.

Not only that, but there’s a very good proposal to add ‘where’ clauses to associated types in the protocols themselves, which will likely further reduce the verbosity of the constraints you need to specify at each declaration site. https://github.com/hartbit/swift-evolution/blob/9acd75abfbe626bbb3f9458cc3f6edb1d1f88c95/proposals/XXXX-associated-types-constraints.md

And then we have generic typealiases and generalised existentials, which would allow us to wrap those ‘where’ clauses in to something much more intelligible to a human being at first glance. ‘StringCollection’ or ‘CollectionOfStrings’ is much clearer than <C:Collection where C.Element==String>, no matter how you chop it up.

If I look at the other proposals, and where we are headed with much more expressive typealiases and associated types, I just feel that that’s the future: that’s the “swift’ way. It’s like type inference - all of the strict constraints are still there under-the-hood, but you’re able to work at a much clearer and more obvious abstraction level. This proposal pulls us further away from things like ‘obviousness’, and like I said, simply feels like an inelegant solution.

At the very least, I think we should shelve the discussion until the larger expansion of typealiases, etc is complete. We should re-evaluate at that time, with a bigger set of more general-purpose tools to produce readable code.

···

On 14 May 2016, at 22:28, L. Mihalkovic via swift-evolution <swift-evolution@swift.org> wrote:

On May 14, 2016, at 9:43 PM, Pyry Jahkola via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Tony & Haravikk,

(Reformatting your quoted examples just a bit…)

It enables things like:
    func someMethod<S : SequenceType, T>(value: S) -> AnySequence<T>
        where S.Generator.Element == T { ... }

I'm not assuming that. Under the current syntax, I would format your example as:

    func someMethod<
        S : SequenceType, T
        where S.Generator.Element == T
    >(value: S) -> AnySequence<T> {
        ...
    }

You are both right here, but please note that the proposal still also allows moving all constraints to the `where` clause:

    func someMethod<S, T>(value: S) -> AnySequence<T>
        where S : SequenceType,
              S.Generator.Element == T
    {
        ...
    }

just like Swift 2 allows doing so within the `<...>` brackets:

    func someMethod<S, T
        where S : SequenceType, S.Generator.Element == T
    >(value: S) -> AnySequence<T> {
        ...
    }

The reason I'd recommend that style for anything but simple constraints is because:

1) It makes the call site `let items = someMethod(value: things)` lightest to visually match to the declaration, because the only thing between the function name and its argument list is the `<...>` bracketed list of introduced generic types which you'll expect to see in the function signature and constraints.

2) In general, the `where` constraints really apply to the whole function/type declaration, not just a single generic parameter.

3) It was claimed that all constraints should go right next to the introduction of the generic parameters. But that isn't the whole case because Swift also applies implicit constraints onto any generic parameters that are used in constrained positions. If that wasn't clearly said, take the following example in Swift 2.x:

    func aMethod<S : SequenceType, T where S.Generator.Element == T>(value: S) -> Set<T> {
        return Set(value)
    }

That declaration actually makes you wait all the way until the return type `Set<T>` until you learn that `T` must also necessarily be `Hashable`. So I don't see how it's that different if the `where` clause isn't right next to the generic type arguments' introduction:

    func aMethod<S, T>(value: S) -> Set<T> // FWIW, this line contains what I usually have in mind when browsing code.
        where // T : Hashable, // (implicit)
              S : SequenceType,
              S.Generator.Element == T
    {
        return Set(value)
    }

— Pyry

PS. Besides, neither the original example nor mine was really fair; you don't need `where` for these. Instead, you'd just write:

    func someMethod<S : SequenceType>(value: S) -> AnySequence<S.Generator.Element> {
        ...
    }

which SE-0081 has nothing to argue for or against.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Why do you think that?

-Thorsten

···

Am 11.05.2016 um 03:56 schrieb Joe Groff via swift-evolution <swift-evolution@swift.org>:

On May 10, 2016, at 4:19 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

On May 10, 2016, at 3:46 PM, Jordan Rose via swift-evolution <swift-evolution@swift.org> wrote:

I think actual keyword “where” provides enough of a delimiter that it won’t be hard to put something before it, and it seems unlikely to me that we would want to add anything after it without some other delimiter. So I’m not too concerned.

Yeah, that’s my feeling as well.

One conceivable use of `where` that this would shut the door on: infix `where` for generalized existentials, e.g. `Protocol where AssociatedType == Int` could be the Protocol existential with Self.AssociatedType constrained to Int.

Hi Karl,

As author of this proposal, the one about constraints on associated types, and the one on type-aliases in protocols (all from the Generics Manifesto - original authorship to Douglas Gregor) I’d like to provide additional reasoning behind my wish to push this proposal through, as a whole.

First of all, there is a personal preference. I’ve used C# for many many years, which has its where clause at the end of the declaration (like this proposal), and I’ve used Swift since its unveiling. The experience with using both styles for several years makes me favour this proposal’s syntax because I find it much easier to read and format for readability.

Constraints on associated type will provide more expressivity but I doubt it will greatly reduce protocol constraint clauses in a majority of cases. And yes, type-aliases in protocols will shorten clauses, but I still think they will more readable with the where clause at the end.

For example, here is a method I took (as-is) from the Standard Library which has a few constraints, and which I further simplified if we imagine that Sequence has an Element typealias for Iterator.Element:

internal func _arrayOutOfPlaceReplace<
  B : _ArrayBufferProtocol, C : Collection
  where
  C.Element == B.Element,
  B.Index == Int

(

  _ source: inout B, _ bounds: Range<Int>, _ newValues: C, _ insertCount: Int
) {

See how the Standard Library authors formatted it for readability and how as a consequence arguments which use the generic types are further apart from the declaration of those generic types. But with this proposal, the declaration might be formatted to:

internal func _arrayOutOfPlaceReplace<B, C>(_ source: inout B, _ bounds: Range<Int>, _ newValues: C, _ insertCount: Int) where
  B : _ArrayBufferProtocol,
  C : Collection,
  C.Iterator.Element == B.Element,
  B.Index == Int
{

Do you need believe this is now more readable?

David.

···

On 15 May 2016, at 02:26, Karl Wagner via swift-evolution <swift-evolution@swift.org> wrote:

There is a lot not to like about the idea; even if it was optional. Personally, I feel the problem is solved in a much, much more elegant manner by other proposals.

Firstly, the stuff after the ‘where’ clause is getting shorter once typealiases come to protocols. C.Iterator.Element become C.Element. In this one example, that’s 18 characters down to 9 - a 50% reduction in length. We tend to use quite expressive names for associated types, so I expect we’ll see similar gains elsewhere from this very simple proposal.

Not only that, but there’s a very good proposal to add ‘where’ clauses to associated types in the protocols themselves, which will likely further reduce the verbosity of the constraints you need to specify at each declaration site. https://github.com/hartbit/swift-evolution/blob/9acd75abfbe626bbb3f9458cc3f6edb1d1f88c95/proposals/XXXX-associated-types-constraints.md

And then we have generic typealiases and generalised existentials, which would allow us to wrap those ‘where’ clauses in to something much more intelligible to a human being at first glance. ‘StringCollection’ or ‘CollectionOfStrings’ is much clearer than <C:Collection where C.Element==String>, no matter how you chop it up.

If I look at the other proposals, and where we are headed with much more expressive typealiases and associated types, I just feel that that’s the future: that’s the “swift’ way. It’s like type inference - all of the strict constraints are still there under-the-hood, but you’re able to work at a much clearer and more obvious abstraction level. This proposal pulls us further away from things like ‘obviousness’, and like I said, simply feels like an inelegant solution.

At the very least, I think we should shelve the discussion until the larger expansion of typealiases, etc is complete. We should re-evaluate at that time, with a bigger set of more general-purpose tools to produce readable code.

This proposal moves `where` after the return type, which would be ambiguous with any infix use of `where` in the type grammar.

-Joe

···

On May 11, 2016, at 6:54 AM, Thorsten Seitz <tseitz42@icloud.com> wrote:

Am 11.05.2016 um 03:56 schrieb Joe Groff via swift-evolution <swift-evolution@swift.org>:

On May 10, 2016, at 4:19 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

On May 10, 2016, at 3:46 PM, Jordan Rose via swift-evolution <swift-evolution@swift.org> wrote:

I think actual keyword “where” provides enough of a delimiter that it won’t be hard to put something before it, and it seems unlikely to me that we would want to add anything after it without some other delimiter. So I’m not too concerned.

Yeah, that’s my feeling as well.

One conceivable use of `where` that this would shut the door on: infix `where` for generalized existentials, e.g. `Protocol where AssociatedType == Int` could be the Protocol existential with Self.AssociatedType constrained to Int.

Why do you think that?