[Pitch] Moving where Clauses Out Of Parameter Lists

I'm with Joe here on not banning it. Having the key constraint up front seems make it easier to grasp the goal of the generic function with a quick glance.

Flexibility around the constraint already exist, as one can currently write:

func foo<C where C: Collection>(x: C) -> C.Element

But probably few do so (maybe just because it's longer to type)

Dany

···

Le 6 avr. 2016 à 16:03, Joe Groff via swift-evolution <swift-evolution@swift.org> a écrit :

On Apr 6, 2016, at 12:52 PM, Pyry Jahkola <pyry.jahkola@iki.fi> wrote:

Joe,

Just from your experience on this topic, is there any reason not to also move the primary constraints into the trailing `where` clause?

So instead of what you wrote, we'd have it this way:

   func foo<T, U>(x: T, y: U) -> Result<T,U>
      where T: Foo, U: Bar, T.Foo == U.Bar /*, etc. */
   {
   }

…as well as:

   struct Foo<T, U>
      where T: Foo, U: Bar, T.Foo == U.Bar
   {
   }

Like I said earlier in this thread, I think this would also make the `extension` syntax more uniform with types (by turning generic parameters into strictly locally visible things):

   extension Foo<T, U> where U == Baz { // (Could've used X and Y here as well.)
       // Now it's clear where the names T and U come from.
       var bazzes: [U] { return ... }
   }

It's a judgment call. It's my feeling that in many cases, a generic parameter is constrained by at least one important protocol or base class that's worth calling out up front, so it's reasonable to allow things like 'func foo<C: Collection>(x: C) -> C.Element' without banishing the 'Collection' constraint too far from the front of the declaration.

I would actually move them as far as after everything else, and right before the definition body. For the above function that would mean:

func anyCommonElements<T, U>(lhs: T, _ rhs: U) -> Bool
   where T : SequenceType,
         U : SequenceType,
         T.Generator.Element: Equatable,
         T.Generator.Element == U.Generator.Element
{
   ...
}

That would make the definition look closer to what the call site looks like.

The same would work for generic types too:

public struct Dictionary<Key, Value>
   where Key : Hashable
{
  ...
}

Another nice thing about this style is that, in principle, I think it could be extended to specify requirements on non-type parameter values.

   func ..< <Element: Incrementable>(lhs: Element, rhs: Element) -> Range<Element>
       where Element: Comparable, lhs <= rhs {
       …
   }

I'm not saying we must or even should include that feature, merely that it gives us a nice syntactic slot to use if we choose to do so later.

I know you're not proposing that feature right now, but want to understand how you expect it to work. It looks to me like this starts to enter design by contract territory. Would the predicate behave as if it was part of a precondition?

···

Sent from my iPad
On Apr 6, 2016, at 7:13 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

--
Brent Royal-Gordon
Architechies

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

This is an excellent idea: +1!

If `where` is left on a previous line, it would also appear more in line with `throws`:

func anyCommonElements<T, U>(lhs: T, _ rhs: U) -> Bool where
    T : SequenceType,
    U : SequenceType,
    T.Generator.Element: Equatable,
    T.Generator.Element == U.Generator.Element
{
    ...
}

milos

···

On 6 Apr 2016, at 19:35, Pyry Jahkola via swift-evolution <swift-evolution@swift.org> wrote:

func anyCommonElements<T, U>(lhs: T, _ rhs: U) -> Bool
    where T : SequenceType,
          U : SequenceType,
          T.Generator.Element: Equatable,
          T.Generator.Element == U.Generator.Element
{
    ...
}

With `where` at the end, the Standard Library function:

  public func != <
    B : Equatable,
    C : Equatable,
    D : Equatable,
    E : Equatable,
    F : Equatable
  > (lhs: (A, B, C, D, E, F), rhs: (A, B, C, D, E, F)) -> Bool

becomes:

  public func != (lhs: (A, B, C, D, E, F), rhs: (A, B, C, D, E, F)) -> Bool where <
    B : Equatable,
    C : Equatable,
    D : Equatable,
    E : Equatable,
    F : Equatable
  >
milos

···

A : Equatable,
    A : Equatable,

On 6 Apr 2016, at 19:35, Pyry Jahkola via swift-evolution <swift-evolution@swift.org> wrote:

On 06 Apr 2016, at 21:30, Developer via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

If you've ever gotten to the point where you have a sufficiently generic interface to a thing and you need to constrain it, possibly in an extension, maybe for a generic free function or operator, you know what a pain the syntax can be for these kinds of operations.

+1 already!

Or, if you're feeling ambitious, even

func anyCommonElements <T, U>
where T : SequenceType, U : SequenceType,
T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element
(lhs: T, _ rhs: U) -> Bool

I would actually move them as far as after everything else, and right before the definition body. For the above function that would mean:

func anyCommonElements<T, U>(lhs: T, _ rhs: U) -> Bool
    where T : SequenceType,
          U : SequenceType,
          T.Generator.Element: Equatable,
          T.Generator.Element == U.Generator.Element
{
    ...
}

That would make the definition look closer to what the call site looks like.

The same would work for generic types too:

public struct Dictionary<Key, Value>
    where Key : Hashable
{
   ...
}

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

This almost seems like it could work so that it didn't even need the bracketed parts to be able to figure out the types:

func anyCommonElements(lhs: T, _ rhs: U) -> Bool where
   T : SequenceType,
   U : SequenceType,
   T.Generator.Element: Equatable,
   T.Generator.Element == U.Generator.Element
{}

But if the brackets are kept, we may be able to do away with commas? For example, this Standard Library function:

    public func + <
        C : RangeReplaceableCollectionType,
        S : SequenceType
        where S.Generator.Element == C.Generator.Element
    > (lhs: C, rhs: S) -> C

would become:

    public func + (lhs: C, rhs: S) -> C where <
        C : RangeReplaceableCollectionType
        C : SequenceType
        S.Generator.Element == C.Generator.Element
    >

Brackets may also be needed for the api view of the library.

milos

···

On 6 Apr 2016, at 19:48, Sean Heber <sean@fifthace.com> wrote:

For example, this Standard Library function:

    public func + <
        C : RangeReplaceableCollectionType,
        S : SequenceType
        where S.Generator.Element == C.Generator.Element
    > (lhs: C, rhs: S) -> C

would become:

    public func + (lhs: C, rhs: S) -> C where <
        C : RangeReplaceableCollectionType
        C : SequenceType
        S.Generator.Element == C.Generator.Element
    >

As for structs, this Standard Library struct:

  public struct FlattenBidirectionalCollection <Base : CollectionType where Base.Generator.Element : CollectionType, Base.Index : BidirectionalIndexType, Base.Generator.Element.Index : BidirectionalIndexType> : CollectionType { … }

… could become:

  public struct FlattenBidirectionalCollection<Base> : CollectionType where <
     Base : CollectionType
     Base.Generator.Element : CollectionType
     Base.Index : BidirectionalIndexType
     Base.Generator.Element.Index : BidirectionalIndexType
  > { … }

milos

A big +1 to this notation.

···

On 06 Apr 2016, at 20:47, Milos Rankovic via swift-evolution <swift-evolution@swift.org> wrote:

On 6 Apr 2016, at 19:35, Pyry Jahkola via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

func anyCommonElements<T, U>(lhs: T, _ rhs: U) -> Bool
    where T : SequenceType,
          U : SequenceType,
          T.Generator.Element: Equatable,
          T.Generator.Element == U.Generator.Element
{
    ...
}

This is an excellent idea: +1!

If `where` is left on a previous line, it would also appear more in line with `throws`:

func anyCommonElements<T, U>(lhs: T, _ rhs: U) -> Bool where
    T : SequenceType,
    U : SequenceType,
    T.Generator.Element: Equatable,
    T.Generator.Element == U.Generator.Element
{
    ...
}

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

The same would work for generic types too:

public struct Dictionary<Key, Value>
    where Key : Hashable
{
   ...
}

And I'm not sure if people feel the same as me, but I haven't been happy with the current way generic arguments (such as Key and Value above) magically appear in type extensions but are inaccessible from anywhere else and can't be made public (`public typealias Key = Key` is an error).

The above syntax would make it possible to use whatever identifiers locally so that it's clear what they are:

extension Dictionary<K, V>
    // (unclear if `where K : Hashable` should be repeated here, though)
{
    ...
}

extension Array<T>
    where T : Comparable
{
    ...
}

extension Array<T>
    where T == String
{
    ...
}

etc.

— Pyry

This almost seems like it could work so that it didn't even need the bracketed parts to be able to figure out the types:

func anyCommonElements(lhs: T, _ rhs: U) -> Bool where
   T : SequenceType,
   U : SequenceType,
   T.Generator.Element: Equatable,
   T.Generator.Element == U.Generator.Element
{}

I'd still keep the generic arguments listed there in the brackets if only for the following reasons:

1. The new names get introduced (in `<...>`) before their first use. So if you happened to name one of them `String`, it would be clear that you didn't mean `Swift.String`.

2. It's been sometimes wished that you could explicitly specify which specialisation you want to use, e.g. when passing a function into a handler (e.g. `let operation = anyCommonElements<[Int], [Int]>(_:_:)`).

3. How would you otherwise mention a generic type if there were no constraints for it? I think the suggested form:

extension Array<T> {
    // no constraints needed (not for T above, not for U below)
    func map<U>(transform: T -> U) -> Array<U> { ... }
}

reads better than this:

extension Array<T> {
    // Wait what, where did U come from?
    func map(transform: T -> U) -> Array<U> { ... }
}

— Pyry

I know you're not proposing that feature right now, but want to understand how you expect it to work. It looks to me like this starts to enter design by contract territory. Would the predicate behave as if it was part of a precondition?

I suppose I imagine it as equivalent to a precondition() placed at the call site, rather than inside the function. If the compiler can prove that the precondition will be violated, it can refuse to compile the call. But I haven't thought deeply about it, so I don't really know for sure.

···

--
Brent Royal-Gordon
Architechies

Another +1 to `where` at the end.

···

On Wed, Apr 6, 2016 at 10:33 PM, Matt Whiteside via swift-evolution < swift-evolution@swift.org> wrote:

+1 to moving the `where` clause after the function signature.

-Matt

> On Apr 6, 2016, at 12:36, Joe Groff via swift-evolution < > swift-evolution@swift.org> wrote:
>
>
>> On Apr 6, 2016, at 11:30 AM, Developer via swift-evolution < > swift-evolution@swift.org> wrote:
>>
>> If you've ever gotten to the point where you have a sufficiently
generic interface to a thing and you need to constrain it, possibly in an
extension, maybe for a generic free function or operator, you know what a
pain the syntax can be for these kinds of operations. For example, the
Swift book implements this example to motivate where clauses
>>
>> func anyCommonElements <T: SequenceType, U: SequenceType where
T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element>
(lhs: T, _ rhs: U) -> Bool
>>
>> This is noisy and uncomfortable to my eyes, and almost impossible to
align correctly. Per a short discussion on Twitter with Joe Groff and
Erica Sadun, I'd like so see what the community feels about moving the
where clause out of the angle brackets. So that example becomes
>>
>> func anyCommonElements <T: SequenceType, U: SequenceType>
>> where T.Generator.Element: Equatable, T.Generator.Element ==
U.Generator.Element
>> (lhs: T, _ rhs: U) -> Bool
>>
>> Or, if you're feeling ambitious, even
>>
>> func anyCommonElements <T, U>
>> where T : SequenceType, U : SequenceType,
>> T.Generator.Element: Equatable, T.Generator.Element ==
U.Generator.Element
>> (lhs: T, _ rhs: U) -> Bool
>>
>> Thoughts?
>
> I think this is a good idea, though I would put the `where` clause after
the function signature:
>
> func foo<T: Foo, U: Bar>(x: T, y: U) -> Result<T,U>
> where T.Foo == U.Bar /*, etc. */
> {
> }
>
> As others noted, it's also appealing to do this for type declarations
too:
>
> struct Foo<T: Foo, U: Bar>
> where T.Foo == U.Bar
> {
> }
>
> and that gives a consistent feeling with extensions and protocol
declarations.
>
> -Joe
> _______________________________________________
> 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

--
Trent Nadeau

Joe Groff wrote:

It's a judgment call. It's my feeling that in many cases, a generic parameter is constrained by at least one important protocol or base class that's worth calling out up front, so it's reasonable to allow things like 'func foo<C: Collection>(x: C) -> C.Element' without banishing the 'Collection' constraint too far from the front of the declaration.

Fair enough. I think it would be clearer if all the constraints appeared in one standard place (in the `where` clause).

— Pyry

I'm hoping this extends to type values.

struct StructWithClosure
{
   let closure : (lhs: Element, rhs:Element) -> Range<Element> where
Element : Incrementable, Comparable
}

or for that matter, protocol values:

struct StructWithIntCollectionType
{
    let collection : C where C : CollectionType, C.Element == Int
}

···

On Thu, Apr 7, 2016 at 1:13 AM, Brent Royal-Gordon via swift-evolution < swift-evolution@swift.org> wrote:

> I would actually move them as far as after everything else, and right
before the definition body. For the above function that would mean:
>
> func anyCommonElements<T, U>(lhs: T, _ rhs: U) -> Bool
> where T : SequenceType,
> U : SequenceType,
> T.Generator.Element: Equatable,
> T.Generator.Element == U.Generator.Element
> {
> ...
> }
>
> That would make the definition look closer to what the call site looks
like.
>
> The same would work for generic types too:
>
> public struct Dictionary<Key, Value>
> where Key : Hashable
> {
> ...
> }

Another nice thing about this style is that, in principle, I think it
could be extended to specify requirements on non-type parameter values.

        func ..< <Element: Incrementable>(lhs: Element, rhs: Element) ->
Range<Element>
                where Element: Comparable, lhs <= rhs {
                …
        }

I'm not saying we must or even should include that feature, merely that it
gives us a nice syntactic slot to use if we choose to do so later.

--
Brent Royal-Gordon
Architechies

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

I like the idea, I find the beginning of a declaration too cluttered and it
obscures the main purpose. Like Brent I am wary of the design by contract
(DBC) bit, `lhs <= rhs`. DBC is probably for a separate discussion, but
moving the where clause would probably help.

  -- Howard.

···

On 7 April 2016 at 10:36, Matthew Johnson via swift-evolution < swift-evolution@swift.org> wrote:

Sent from my iPad

On Apr 6, 2016, at 7:13 PM, Brent Royal-Gordon via swift-evolution < > swift-evolution@swift.org> wrote:

>> I would actually move them as far as after everything else, and right
before the definition body. For the above function that would mean:
>>
>> func anyCommonElements<T, U>(lhs: T, _ rhs: U) -> Bool
>> where T : SequenceType,
>> U : SequenceType,
>> T.Generator.Element: Equatable,
>> T.Generator.Element == U.Generator.Element
>> {
>> ...
>> }
>>
>> That would make the definition look closer to what the call site looks
like.
>>
>> The same would work for generic types too:
>>
>> public struct Dictionary<Key, Value>
>> where Key : Hashable
>> {
>> ...
>> }
>
> Another nice thing about this style is that, in principle, I think it
could be extended to specify requirements on non-type parameter values.
>
> func ..< <Element: Incrementable>(lhs: Element, rhs: Element) ->
Range<Element>
> where Element: Comparable, lhs <= rhs {
> …
> }
>
> I'm not saying we must or even should include that feature, merely that
it gives us a nice syntactic slot to use if we choose to do so later.

I know you're not proposing that feature right now, but want to understand
how you expect it to work. It looks to me like this starts to enter design
by contract territory. Would the predicate behave as if it was part of a
precondition?

> --
> Brent Royal-Gordon
> Architechies
>
> _______________________________________________
> 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

Because I am a mailing list noob, my email wasn't CC'd to all. So here we go again:

Big +1 from me.

I expected not to like this syntax but I believe it makes it far clearer. It always felt backwards to me to have to come up with all the constraints before the function signature. Maybe this is moot because you should already know what the function should look like before writing. But we are all human and things may change as we are writing it, resulting in a constant going back and forth from the signature to the constraints.

It reads much more naturally (and I think it's easier to write) when the where clause is after the signature because you have to look *back* to the parameters in the function instead of looking forward. And when having to look forward, you have to parse a possibly long list of constraints before even finding the signature. Repeat this possibly for each constraint and there is some mental overload there.

With the where at the end, you've already read the function signature and the signature is in a known easy to find place when looking back at it.

So in summary:
- it reads more naturally
- more comfortable on the eyes
- easier to find the function signature when looking back after reading the constraints

This all leads to less mental overload IMO

Brandon

···

On Apr 6, 2016, at 2:37 PM, Shawn Erickson via swift-evolution <swift-evolution@swift.org> wrote:

On Wed, Apr 6, 2016 at 11:36 AM Pyry Jahkola via swift-evolution <swift-evolution@swift.org> wrote:

On 06 Apr 2016, at 21:30, Developer via swift-evolution <swift-evolution@swift.org> wrote:

If you've ever gotten to the point where you have a sufficiently generic interface to a thing and you need to constrain it, possibly in an extension, maybe for a generic free function or operator, you know what a pain the syntax can be for these kinds of operations.

+1 already!

Or, if you're feeling ambitious, even

func anyCommonElements <T, U>
where T : SequenceType, U : SequenceType,
T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element
(lhs: T, _ rhs: U) -> Bool

I would actually move them as far as after everything else, and right before the definition body. For the above function that would mean:

func anyCommonElements<T, U>(lhs: T, _ rhs: U) -> Bool
    where T : SequenceType,
          U : SequenceType,
          T.Generator.Element: Equatable,
          T.Generator.Element == U.Generator.Element
{
    ...
}

That would make the definition look closer to what the call site looks like.

The same would work for generic types too:

public struct Dictionary<Key, Value>
    where Key : Hashable
{
   ...
}

I very much like this suggestion.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I quite like this variation, so I’m a +1 for that.

However, I think this would be greatly helped if we could define protocol generics more like type generics like so:

  protocol Foo<Element> { … }
  func anyStringFoo(lhs:Foo<String>) { … }

But yeah, for the more complicated cases, it makes a lot of sense to relocate the where clause away from the main signature. I’d maybe still allow declarations of type though like-so:

  func anyCommonElements<T:SequenceType, U:SequenceType>(lhs:T, _ rhs:U) -> Bool
    where T.Generator.Element:Equatable, T.Generator.Element == U.Generator.Element

Perhaps allowing us the choice of doing it this way at least.

···

On 6 Apr 2016, at 19:35, Pyry Jahkola via swift-evolution <swift-evolution@swift.org> wrote:

On 06 Apr 2016, at 21:30, Developer via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

If you've ever gotten to the point where you have a sufficiently generic interface to a thing and you need to constrain it, possibly in an extension, maybe for a generic free function or operator, you know what a pain the syntax can be for these kinds of operations.

+1 already!

Or, if you're feeling ambitious, even

func anyCommonElements <T, U>
where T : SequenceType, U : SequenceType,
T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element
(lhs: T, _ rhs: U) -> Bool

I would actually move them as far as after everything else, and right before the definition body. For the above function that would mean:

func anyCommonElements<T, U>(lhs: T, _ rhs: U) -> Bool
    where T : SequenceType,
          U : SequenceType,
          T.Generator.Element: Equatable,
          T.Generator.Element == U.Generator.Element
{
    ...
}

That would make the definition look closer to what the call site looks like.

The same would work for generic types too:

public struct Dictionary<Key, Value>
    where Key : Hashable
{
   ...
}

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

I had this thought too. The possibilities that this syntax change suggests for compile time evaluation are very interesting, in my opinion.

-Matt

···

On Apr 6, 2016, at 17:13, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

Another nice thing about this style is that, in principle, I think it could be extended to specify requirements on non-type parameter values.

What’s up with this great idea? Can’t see a proposal on swift-evolution anywhere.

···

On 08 Apr 2016, at 08:15, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Apr 6, 2016, at 11:30 AM, Developer via swift-evolution <swift-evolution@swift.org> wrote:

If you've ever gotten to the point where you have a sufficiently generic interface to a thing and you need to constrain it, possibly in an extension, maybe for a generic free function or operator, you know what a pain the syntax can be for these kinds of operations. For example, the Swift book implements this example to motivate where clauses

func anyCommonElements <T: SequenceType, U: SequenceType where T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element> (lhs: T, _ rhs: U) -> Bool

This is noisy and uncomfortable to my eyes, and almost impossible to align correctly. Per a short discussion on Twitter with Joe Groff and Erica Sadun, I'd like so see what the community feels about moving the where clause out of the angle brackets. So that example becomes

func anyCommonElements <T: SequenceType, U: SequenceType>
where T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element
(lhs: T, _ rhs: U) -> Bool

Or, if you're feeling ambitious, even

func anyCommonElements <T, U>
where T : SequenceType, U : SequenceType,
T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element
(lhs: T, _ rhs: U) -> Bool

Thoughts?

+1, long overdue. Please keep basic constraints (ones expressible without a ‘where’ clause, like simple conformances) inline though.

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

That's definitely a reasonable position worth discussing.

-Joe

···

On Apr 6, 2016, at 1:21 PM, Pyry Jahkola <pyry.jahkola@iki.fi> wrote:

Joe Groff wrote:

It's a judgment call. It's my feeling that in many cases, a generic parameter is constrained by at least one important protocol or base class that's worth calling out up front, so it's reasonable to allow things like 'func foo<C: Collection>(x: C) -> C.Element' without banishing the 'Collection' constraint too far from the front of the declaration.

Fair enough. I think it would be clearer if all the constraints appeared in one standard place (in the `where` clause).

Another factor here is that we've been planning for a while for generic parameters to types to be exposed as implicit member typealiases, since they already conflict with the namespace for member typealiases. Therefore it's important to name generic parameters to types well, but less important to do so for generic parameters for functions. (They're also much less likely to be ad hoc for types; there has to be something that describes the relation between the Self type and the parameter, while the function might not have anything more interesting than "operand".)

This is also a minor point against declaring generic parameters for extensions, since they would have to match up. We also do need a syntax some day to represent new parameters:

// For expository purposes only:
extension <T> Array where Element == Optional<T>

But that deserves its own proposal. I just don't want us to paint ourselves into a corner.

Jordan

···

On Apr 6, 2016, at 16:52, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

On Apr 6, 2016, at 5:45 PM, David Waite via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Apr 6, 2016, at 1:36 PM, Joe Groff via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I think this is a good idea, though I would put the `where` clause after the function signature:

func foo<T: Foo, U: Bar>(x: T, y: U) -> Result<T,U>
   where T.Foo == U.Bar /*, etc. */
{
}

A bit of a meta-argument:

It is very common to use single-capital letter generic parameters, and the API style does not give guidance around the naming of generic parameters.

However in my humble-but-opinionated view, they are effectively scope-bound, dynamic type aliases. Declaring func "foo<T>" is like declaring “var i”, but its forgiven since coming up with a good, concise name for such a type alias can be hard.

The standard library seems inconsistent about this as well:

func == <A : Equatable, B : Equatable>(_: (A, B), rhs: (A, B))

vs.

func == <Key : Equatable, Value : Equatable>(_: [Key : Value], rhs: [Key : Value])

The argument I bring up is that naming of the generic parameters may wind up affecting whether the code is clearer having type constraints and the where clause within the brackets or trailing the function. It is important to take this into account and compare both apples to apples and oranges to oranges when evaluating syntax.

(or, change the API guide and standard library to discourage either apples or oranges)

-DW

I'll keep this short. IMO:

* Dictionaries have semantics, so Key/Value makes sense.
* Truly "generic" equatable values do not, so A and B are simple stand-ins.
* Always prefer named tokens when there are actual semantics (Element, Wrapped, etc).

This may or may not be appropriate for inclusion in the API guidelines.