[swift-evolution-announce] [Review] SE-0089: Replace protocol<P1, P2> syntax with Any<P1, P2>

Thanks for all your thoughtful replies.

I'm not really invested in arguing this much further, as it's mainly a
stylistic thing that I could live with and also probably a hopeless battle
(given how everyone else disagrees). But I would like to address a few
final points.

(inline)

Turning it around, we don’t have to put parentheses around function types
and nobody complains about it being problematic even for higher-order
functions with several steps before the final result.

Function types have a very regular syntax, especially now that 0066 was
accepted (which, I admit, was very controversal itself):

( <one or more types> ) -> (tuple)
or
( <one or more types> ) -> SingleTypeWithNoSpaces
or
( <one or more types> ) -> GenericType<All, Spaces, Are, Inside, The,

A function type is very easy to visually parse: combine the argument
parens, arrow thing, and the single type that it returns. That being said,
complex function types are probably the most difficult types to read in a
function declaration today, even with this regular structure.

The proposed syntax, which allows arbitrary whitespace outside the context
of a delimiter, would require the user to scan the string comprising the
existential type expression for a very common sigil in order to locate the
endpoint: '=' for variable declarations (which admittedly isn't that bad)
or ',' for functions (which is a lot worse). Not to mention the point Joe
Groff brought up about a generic function with a generic where clause
returning an existential and having everything devolve into a
undifferentiated soup of identifiers.

Does anyone know if users of Ceylon or other languages with the
unparenthesized syntax find it problematic? How would they feel about
being required to use parentheses?

We're trying to establish a syntax that will hopefully be used for things
significantly more complicated than tuple definitions, which are just a
list of types. I think readability is a major concern. Typealiases should
be supported, but they shouldn't be required to make the feature useable.

I agree, but I don’t think they would be required to make the feature
useable just because parentheses are not required. If a developer or team
thinks they are required for clarity / readability, etc they are free to
use them. This is a style issue that should be addressed by a linter, not
the formal syntax of the language.

It is a style issue, but so is (Int) -> T versus Int -> T and a lot of
other language details like trailing commas in argument lists, of which the
core team seems to feel pretty strongly about.

Finally, wouldn't we need some delimiter for nested existential
definitions anyways? Now you have the confusing situation where the outside
definition has no delimiters, but the inside ones do:

// Why does the inner existential look fundamentally different than the
outer one?
// Not to mention, visually parsing the boundaries of this type when you
look at it in a function signature
let x : Protocol1, Protocol2, (Protocol 3 where .Foo == Int) where
Protocol2.Bar : Baz

Nested existentials are supported not because it would ever be a good idea
to actually write them. They are supported to allow composition of
existentials:

Perhaps then we should only allow existentials to be nested if a typealias
is used. Swift is, after all, an opinionated language. If a feature is in
the language, it should either be usable directly in an ergonomic way, or
it shouldn't be there at all. Having a self-admittedly "bad" way to nest
literal existential expressions just for consistency when typealiases are
the preferred use case is very unlike Swift.

···

On Fri, May 27, 2016 at 12:06 PM, Matthew Johnson <matthew@anandabits.com> wrote:

typealias P3Int = Protocol 3 where .Foo == Int
let x : Protocol1, Protocol2, P3Int where Protocol2.Bar : Baz

If you are writing the entire type in a single location I expect the
conventional style to be like this:

let x : Protocol1, Protocol2, Protocol 3 where Protocol2.Bar : Baz,
Protocol3.Foo == Int

With all associated types constraints in a single `where` clause as we
other places they are written in Swift.

Maybe I am wrong about that and a different conventional style would
emerge (for example, where clauses clustered with the related protocol).

But *requiring* parentheses is really orthogonal to the style issue of
where and when it is considered *advisable* to use them.

-Matthew

I hope that explains my reasoning.

Best,
Austin

On May 27, 2016, at 9:28 AM, Matthew Johnson <matthew@anandabits.com> > wrote:

Sent from my iPad

On May 27, 2016, at 11:18 AM, Austin Zheng <austinzheng@gmail.com> wrote:

Here's a strawman idea.

What if we go with '&' and 'where', but we enclose the whole thing in
parentheses?

(class & Protocol1 & Protocol2 where .Foo == Int, .Bar : Baz)

There are a couple of reasons I propose this syntax:

- It makes it very clear where the definition of the type begins and ends.
I understand people really despise angle brackets, but I really want some
way to visually delineate the boundaries of the type. Plus, I imagine it
makes syntax a little easier to parse and preemptively forbids some
ambiguities.

- It's a structural, not nominal, type, like a tuple, so it uses parens as
well. This reserves "<" and ">" for generic types.

- The '&' is easily understood - "Protocol1" *and* "Protocol2". It's also
a signal that order doesn't matter - just like how order matters with
things that use commas, like argument lists, tuples, and array members,
order doesn't generally matter with bitwise or logical 'and' operators.

- If we ever decide to have union types, we have a very elegant third form
of nominal type syntax that naturally falls out: (MyClass1 | MyClass2 |
MyClass3).

Thoughts?

Generally in favor. But I would not require the parentheses. I believe
they would be allowed optionally automatically, just as (Int) is the same
as Int (because single element tuples don't exist and the underlying type
is used directly instead). It seems better to leave parentheses up to a
matter of style.

Austin

On May 27, 2016, at 9:07 AM, Thorsten Seitz via swift-evolution < > swift-evolution@swift.org> wrote:

Am 27.05.2016 um 16:54 schrieb Matthew Johnson <matthew@anandabits.com>:

On May 27, 2016, at 8:18 AM, Thorsten Seitz via swift-evolution < > swift-evolution@swift.org> wrote:

Personally I think `&` is more lightweight (and it is established in other
languages like Ceylon and Typescript) and `where` is more expressive (and
established in Swift for introducing constraints), so I would stay with
these.

I agree. If we can make `&` with `where` work syntactically it would be
nice to go in this lighter weight direction. If we decide to do that the
question then becomes what to do with `protocol`. Would it be feasible to
replace it with `&` in Swift 3 if we decide on that direction?

Yep. `protocol` should be replaced with `&` in that case.

-Thorsten

-Thorsten

Am 27.05.2016 um 14:34 schrieb Vladimir.S <svabox@gmail.com>:

Btw, in case we have `where` keyword in syntax related to types/protocols
(when defining constrains. and not some symbol like '>>'.. don't know, for
example), why we can't have 'and' keyword also when discuss the syntax of
type/protocol conjunction?
I.e.

let x: P and Q
let x: P and Q where P.T == Q.T
let x: P and Q and R

or, for consistency, as I understand it, we should have
let x: P & Q >> P.T == Q.T

On 27.05.2016 11:55, Thorsten Seitz via swift-evolution wrote:

We could just write

let x: P & Q
instead of
let x: Any<P, Q>

let x: Collection where .Element: P
instead of
let x: Any<Collection where .Element: P>

let x: P & Q where P.T == Q.T
instead of
let x: Any<P, Q where P.T == Q.T>

let x: P & Q & R
instead of
let x: Any<P, Q, R>

let x: Collection
instead of
let x: Any<Collection>

This would avoid the confusion of Any<T1, T2> being something completely
different than a generic type (i.e. order of T1, T2 does not matter whereas
for generic types it is essential).

-Thorsten

Am 26.05.2016 um 20:11 schrieb Adrian Zubarev via swift-evolution
<swift-evolution@swift.org <mailto:swift-evolution@swift.org
<swift-evolution@swift.org>>>:

Something like |type<…>| was considered at the very start of the whole
discussion (in this thread
<
[swift-evolution] [Pitch] merge types and protocols back together with type<Type, Protocol, ...>
>),
but it does not solve the meaning of an existential type and also might
lead to even more confusion.

From my perspective I wouldn’t use parentheses here because it looks more
like an init without any label |Type.init(…)| or |Type(…)|. I could live
with |Any[…]| but this doesn’t look shiny and Swifty to me. Thats only my
personal view. ;)

--
Adrian Zubarev
Sent with Airmail

Am 26. Mai 2016 bei 19:48:04, Vladimir.S via swift-evolution
(swift-evolution@swift.org <mailto:swift-evolution@swift.org
<swift-evolution@swift.org>>) schrieb:

Don't think {} is better here, as they also have "established meaning in
Swift today".

How about just Type(P1 & P2 | P3) - as IMO we can think of such
construction as "creation" of new type and `P1 & P2 | P3` could be treated
as parameters to initializer.

func f(t: Type(P1 & P2 | P3)) {..}

On 26.05.2016 20:32, L. Mihalkovic via swift-evolution wrote:
> How about something like Type{P1 & P2 | P3} the point being that "<...>"
has an established meaning in Swift today which is not what is expressed in
the "<P1,P2,P3>" contained inside Any<P1, P2,P3>.
>
>> On May 26, 2016, at 7:11 PM, Dave Abrahams via swift-evolution < > swift-evolution@swift.org <mailto:swift-evolution@swift.org > <swift-evolution@swift.org>>> wrote:
>>
>>
>>> on Thu May 26 2016, Adrian Zubarev <swift-evolution@swift.org < > mailto:swift-evolution@swift.org <swift-evolution@swift.org>>> wrote:
>>>
>>> There is great feedback going on here. I'd like to consider a few
things here:
>>>
>>> * What if we name the whole thing `Existential<>` to sort out all
>>> confusion?
>>
>> Some of us believe that “existential” is way too theoretical a word to
>> force into the official lexicon of Swift. I think “Any<...>” is much
>> more conceptually accessible.
>>
>>>
>>> This would allow `typealias Any = Existential<>`. * Should
>>> `protocol A: Any<class>` replace `protocol A: class`? Or at least
>>> deprecate it. * Do we need `typealias AnyClass = Any<class>` or do we
>>> want to use any class requirement existential directly? If second, we
>>> will need to allow direct existential usage on protocols (right now we
>>> only can use typealiases as a worksround).
>>
>> --
>> Dave
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org <mailto:swift-evolution@swift.org
<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
<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
<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
<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

I think the parentheses are the fundamental aspect of the suggestion :).

Yes I know. I guess we disagree on this point. It seems like a matter of style to me, not something to require.

Let me turn the question around. If tuples were declared like this:

let myTuple : Int, String, Bool = (10, "hello", false)

would the type be more or less readable? I find it a lot more difficult to immediately parse than:

let myTuple : (Int, String, Bool) = (10, "hello", false)

At the same time, nobody's complained about tuple type parentheses getting in the way.

I do think these questions are important to consider but remain unconvinced thus far.

In the case of tuples the type syntax matches the usage syntax which is important. That doesn’t apply for existentials.

Turning it around, we don’t have to put parentheses around function types and nobody complains about it being problematic even for higher-order functions with several steps before the final result.

Does anyone know if users of Ceylon or other languages with the unparenthesized syntax find it problematic? How would they feel about being required to use parentheses?

We're trying to establish a syntax that will hopefully be used for things significantly more complicated than tuple definitions, which are just a list of types. I think readability is a major concern. Typealiases should be supported, but they shouldn't be required to make the feature useable.

I agree, but I don’t think they would be required to make the feature useable just because parentheses are not required. If a developer or team thinks they are required for clarity / readability, etc they are free to use them. This is a style issue that should be addressed by a linter, not the formal syntax of the language.

Finally, wouldn't we need some delimiter for nested existential definitions anyways? Now you have the confusing situation where the outside definition has no delimiters, but the inside ones do:

// Why does the inner existential look fundamentally different than the outer one?
// Not to mention, visually parsing the boundaries of this type when you look at it in a function signature
let x : Protocol1, Protocol2, (Protocol 3 where .Foo == Int) where Protocol2.Bar : Baz

Nested existentials are supported not because it would ever be a good idea to actually write them. They are supported to allow composition of existentials:

typealias P3Int = Protocol 3 where .Foo == Int
let x : Protocol1, Protocol2, P3Int where Protocol2.Bar : Baz

If you are writing the entire type in a single location I expect the conventional style to be like this:

let x : Protocol1, Protocol2, Protocol 3 where Protocol2.Bar : Baz, Protocol3.Foo == Int

With all associated types constraints in a single `where` clause as we other places they are written in Swift.

Maybe I am wrong about that and a different conventional style would emerge (for example, where clauses clustered with the related protocol).

But *requiring* parentheses is really orthogonal to the style issue of where and when it is considered *advisable* to use them.

-Matthew

···

On May 27, 2016, at 11:36 AM, Austin Zheng <austinzheng@gmail.com> wrote:

I hope that explains my reasoning.

Best,
Austin

On May 27, 2016, at 9:28 AM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

Sent from my iPad

On May 27, 2016, at 11:18 AM, Austin Zheng <austinzheng@gmail.com <mailto:austinzheng@gmail.com>> wrote:

Here's a strawman idea.

What if we go with '&' and 'where', but we enclose the whole thing in parentheses?

(class & Protocol1 & Protocol2 where .Foo == Int, .Bar : Baz)

There are a couple of reasons I propose this syntax:

- It makes it very clear where the definition of the type begins and ends. I understand people really despise angle brackets, but I really want some way to visually delineate the boundaries of the type. Plus, I imagine it makes syntax a little easier to parse and preemptively forbids some ambiguities.

- It's a structural, not nominal, type, like a tuple, so it uses parens as well. This reserves "<" and ">" for generic types.

- The '&' is easily understood - "Protocol1" *and* "Protocol2". It's also a signal that order doesn't matter - just like how order matters with things that use commas, like argument lists, tuples, and array members, order doesn't generally matter with bitwise or logical 'and' operators.

- If we ever decide to have union types, we have a very elegant third form of nominal type syntax that naturally falls out: (MyClass1 | MyClass2 | MyClass3).

Thoughts?

Generally in favor. But I would not require the parentheses. I believe they would be allowed optionally automatically, just as (Int) is the same as Int (because single element tuples don't exist and the underlying type is used directly instead). It seems better to leave parentheses up to a matter of style.

Austin

On May 27, 2016, at 9:07 AM, Thorsten Seitz via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Am 27.05.2016 um 16:54 schrieb Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>>:

On May 27, 2016, at 8:18 AM, Thorsten Seitz via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Personally I think `&` is more lightweight (and it is established in other languages like Ceylon and Typescript) and `where` is more expressive (and established in Swift for introducing constraints), so I would stay with these.

I agree. If we can make `&` with `where` work syntactically it would be nice to go in this lighter weight direction. If we decide to do that the question then becomes what to do with `protocol`. Would it be feasible to replace it with `&` in Swift 3 if we decide on that direction?

Yep. `protocol` should be replaced with `&` in that case.

-Thorsten

-Thorsten

Am 27.05.2016 um 14:34 schrieb Vladimir.S <svabox@gmail.com <mailto:svabox@gmail.com>>:

Btw, in case we have `where` keyword in syntax related to types/protocols (when defining constrains. and not some symbol like '>>'.. don't know, for example), why we can't have 'and' keyword also when discuss the syntax of type/protocol conjunction?
I.e.

let x: P and Q
let x: P and Q where P.T == Q.T
let x: P and Q and R

or, for consistency, as I understand it, we should have
let x: P & Q >> P.T == Q.T

On 27.05.2016 11:55, Thorsten Seitz via swift-evolution wrote:

We could just write

let x: P & Q
instead of
let x: Any<P, Q>

let x: Collection where .Element: P
instead of
let x: Any<Collection where .Element: P>

let x: P & Q where P.T == Q.T
instead of
let x: Any<P, Q where P.T == Q.T>

let x: P & Q & R
instead of
let x: Any<P, Q, R>

let x: Collection
instead of
let x: Any<Collection>

This would avoid the confusion of Any<T1, T2> being something completely
different than a generic type (i.e. order of T1, T2 does not matter whereas
for generic types it is essential).

-Thorsten

Am 26.05.2016 um 20:11 schrieb Adrian Zubarev via swift-evolution
<swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>>:

Something like |type<…>| was considered at the very start of the whole
discussion (in this thread
<https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160502/016523.html&gt;\),
but it does not solve the meaning of an existential type and also might
lead to even more confusion.

From my perspective I wouldn’t use parentheses here because it looks more
like an init without any label |Type.init(…)| or |Type(…)|. I could live
with |Any[…]| but this doesn’t look shiny and Swifty to me. Thats only my
personal view. ;)

--
Adrian Zubarev
Sent with Airmail

Am 26. Mai 2016 bei 19:48:04, Vladimir.S via swift-evolution
(swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>) schrieb:

Don't think {} is better here, as they also have "established meaning in
Swift today".

How about just Type(P1 & P2 | P3) - as IMO we can think of such
construction as "creation" of new type and `P1 & P2 | P3` could be treated
as parameters to initializer.

func f(t: Type(P1 & P2 | P3)) {..}

On 26.05.2016 20:32, L. Mihalkovic via swift-evolution wrote:
> How about something like Type{P1 & P2 | P3} the point being that "<...>" has an established meaning in Swift today which is not what is expressed in the "<P1,P2,P3>" contained inside Any<P1, P2,P3>.
>
>> On May 26, 2016, at 7:11 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>> wrote:
>>
>>
>>> on Thu May 26 2016, Adrian Zubarev <swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>> wrote:
>>>
>>> There is great feedback going on here. I'd like to consider a few things here:
>>>
>>> * What if we name the whole thing `Existential<>` to sort out all
>>> confusion?
>>
>> Some of us believe that “existential” is way too theoretical a word to
>> force into the official lexicon of Swift. I think “Any<...>” is much
>> more conceptually accessible.
>>
>>>
>>> This would allow `typealias Any = Existential<>`. * Should
>>> `protocol A: Any<class>` replace `protocol A: class`? Or at least
>>> deprecate it. * Do we need `typealias AnyClass = Any<class>` or do we
>>> want to use any class requirement existential directly? If second, we
>>> will need to allow direct existential usage on protocols (right now we
>>> only can use typealiases as a worksround).
>>
>> --
>> Dave
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto: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> <mailto: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> <mailto: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> <mailto: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 <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

Thanks for all your thoughtful replies.

I'm not really invested in arguing this much further, as it's mainly a stylistic thing that I could live with and also probably a hopeless battle (given how everyone else disagrees).

I’ve been in the same place with some of the other stylistic battles. :-)

But I would like to address a few final points.

(inline)

Turning it around, we don’t have to put parentheses around function types and nobody complains about it being problematic even for higher-order functions with several steps before the final result.

Function types have a very regular syntax, especially now that 0066 was accepted (which, I admit, was very controversal itself):

( <one or more types> ) -> (tuple)
or
( <one or more types> ) -> SingleTypeWithNoSpaces
or
( <one or more types> ) -> GenericType<All, Spaces, Are, Inside, The, Brackets>

A function type is very easy to visually parse: combine the argument parens, arrow thing, and the single type that it returns. That being said, complex function types are probably the most difficult types to read in a function declaration today, even with this regular structure.

The proposed syntax, which allows arbitrary whitespace outside the context of a delimiter, would require the user to scan the string comprising the existential type expression for a very common sigil in order to locate the endpoint: '=' for variable declarations (which admittedly isn't that bad) or ',' for functions (which is a lot worse). Not to mention the point Joe Groff brought up about a generic function with a generic where clause returning an existential and having everything devolve into a undifferentiated soup of identifiers.

Does anyone know if users of Ceylon or other languages with the unparenthesized syntax find it problematic? How would they feel about being required to use parentheses?

We're trying to establish a syntax that will hopefully be used for things significantly more complicated than tuple definitions, which are just a list of types. I think readability is a major concern. Typealiases should be supported, but they shouldn't be required to make the feature useable.

I agree, but I don’t think they would be required to make the feature useable just because parentheses are not required. If a developer or team thinks they are required for clarity / readability, etc they are free to use them. This is a style issue that should be addressed by a linter, not the formal syntax of the language.

It is a style issue, but so is (Int) -> T versus Int -> T and a lot of other language details like trailing commas in argument lists, of which the core team seems to feel pretty strongly about.

Fair enough! :-)

Finally, wouldn't we need some delimiter for nested existential definitions anyways? Now you have the confusing situation where the outside definition has no delimiters, but the inside ones do:

// Why does the inner existential look fundamentally different than the outer one?
// Not to mention, visually parsing the boundaries of this type when you look at it in a function signature
let x : Protocol1, Protocol2, (Protocol 3 where .Foo == Int) where Protocol2.Bar : Baz

Nested existentials are supported not because it would ever be a good idea to actually write them. They are supported to allow composition of existentials:

Perhaps then we should only allow existentials to be nested if a typealias is used. Swift is, after all, an opinionated language. If a feature is in the language, it should either be usable directly in an ergonomic way, or it shouldn't be there at all. Having a self-admittedly "bad" way to nest literal existential expressions just for consistency when typealiases are the preferred use case is very unlike Swift.

I think self-admittedly “bad” is a bit of a stretch. I do *think* the conventional style would be to match the rest of Swift. But I’m not *certain* of that. I could see the style Thorsten posted being conventional and useful in some cases:

let x : Protocol1 & (Protocol2 where .Bar : Baz) & (Protocol 3 where .Foo == Int)

I think direct `&` syntax will be most useful when combining two (or maybe three) protocols with no associated types: `Protocol1 & Protocol2` (whether or not we require parens).

Generally I hope we will use type aliases for existentials that are this complex just as we usually bind names to parts of expressions rather than writing large one-liners.

One issue I’m not sure we have addressed is the case of an existential for a single protocol with an associated type constraint `Protocol where .Foo = Int`. Before we settle on a syntax we should be sure that this doesn’t introduce any ambiguity.

-Matthew

···

On May 27, 2016, at 2:26 PM, Austin Zheng <austinzheng@gmail.com> wrote:
On Fri, May 27, 2016 at 12:06 PM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

typealias P3Int = Protocol 3 where .Foo == Int
let x : Protocol1, Protocol2, P3Int where Protocol2.Bar : Baz

If you are writing the entire type in a single location I expect the conventional style to be like this:

let x : Protocol1, Protocol2, Protocol 3 where Protocol2.Bar : Baz, Protocol3.Foo == Int

With all associated types constraints in a single `where` clause as we other places they are written in Swift.

Maybe I am wrong about that and a different conventional style would emerge (for example, where clauses clustered with the related protocol).

But *requiring* parentheses is really orthogonal to the style issue of where and when it is considered *advisable* to use them.

-Matthew

I hope that explains my reasoning.

Best,
Austin

On May 27, 2016, at 9:28 AM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

Sent from my iPad

On May 27, 2016, at 11:18 AM, Austin Zheng <austinzheng@gmail.com <mailto:austinzheng@gmail.com>> wrote:

Here's a strawman idea.

What if we go with '&' and 'where', but we enclose the whole thing in parentheses?

(class & Protocol1 & Protocol2 where .Foo == Int, .Bar : Baz)

There are a couple of reasons I propose this syntax:

- It makes it very clear where the definition of the type begins and ends. I understand people really despise angle brackets, but I really want some way to visually delineate the boundaries of the type. Plus, I imagine it makes syntax a little easier to parse and preemptively forbids some ambiguities.

- It's a structural, not nominal, type, like a tuple, so it uses parens as well. This reserves "<" and ">" for generic types.

- The '&' is easily understood - "Protocol1" *and* "Protocol2". It's also a signal that order doesn't matter - just like how order matters with things that use commas, like argument lists, tuples, and array members, order doesn't generally matter with bitwise or logical 'and' operators.

- If we ever decide to have union types, we have a very elegant third form of nominal type syntax that naturally falls out: (MyClass1 | MyClass2 | MyClass3).

Thoughts?

Generally in favor. But I would not require the parentheses. I believe they would be allowed optionally automatically, just as (Int) is the same as Int (because single element tuples don't exist and the underlying type is used directly instead). It seems better to leave parentheses up to a matter of style.

Austin

On May 27, 2016, at 9:07 AM, Thorsten Seitz via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Am 27.05.2016 um 16:54 schrieb Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>>:

On May 27, 2016, at 8:18 AM, Thorsten Seitz via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Personally I think `&` is more lightweight (and it is established in other languages like Ceylon and Typescript) and `where` is more expressive (and established in Swift for introducing constraints), so I would stay with these.

I agree. If we can make `&` with `where` work syntactically it would be nice to go in this lighter weight direction. If we decide to do that the question then becomes what to do with `protocol`. Would it be feasible to replace it with `&` in Swift 3 if we decide on that direction?

Yep. `protocol` should be replaced with `&` in that case.

-Thorsten

-Thorsten

Am 27.05.2016 um 14:34 schrieb Vladimir.S <svabox@gmail.com <mailto:svabox@gmail.com>>:

Btw, in case we have `where` keyword in syntax related to types/protocols (when defining constrains. and not some symbol like '>>'.. don't know, for example), why we can't have 'and' keyword also when discuss the syntax of type/protocol conjunction?
I.e.

let x: P and Q
let x: P and Q where P.T == Q.T
let x: P and Q and R

or, for consistency, as I understand it, we should have
let x: P & Q >> P.T == Q.T

On 27.05.2016 11:55, Thorsten Seitz via swift-evolution wrote:

We could just write

let x: P & Q
instead of
let x: Any<P, Q>

let x: Collection where .Element: P
instead of
let x: Any<Collection where .Element: P>

let x: P & Q where P.T == Q.T
instead of
let x: Any<P, Q where P.T == Q.T>

let x: P & Q & R
instead of
let x: Any<P, Q, R>

let x: Collection
instead of
let x: Any<Collection>

This would avoid the confusion of Any<T1, T2> being something completely
different than a generic type (i.e. order of T1, T2 does not matter whereas
for generic types it is essential).

-Thorsten

Am 26.05.2016 um 20:11 schrieb Adrian Zubarev via swift-evolution
<swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>>:

Something like |type<…>| was considered at the very start of the whole
discussion (in this thread
<https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160502/016523.html&gt;\),
but it does not solve the meaning of an existential type and also might
lead to even more confusion.

From my perspective I wouldn’t use parentheses here because it looks more
like an init without any label |Type.init(…)| or |Type(…)|. I could live
with |Any[…]| but this doesn’t look shiny and Swifty to me. Thats only my
personal view. ;)

--
Adrian Zubarev
Sent with Airmail

Am 26. Mai 2016 bei 19:48:04, Vladimir.S via swift-evolution
(swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>) schrieb:

Don't think {} is better here, as they also have "established meaning in
Swift today".

How about just Type(P1 & P2 | P3) - as IMO we can think of such
construction as "creation" of new type and `P1 & P2 | P3` could be treated
as parameters to initializer.

func f(t: Type(P1 & P2 | P3)) {..}

On 26.05.2016 20:32, L. Mihalkovic via swift-evolution wrote:
> How about something like Type{P1 & P2 | P3} the point being that "<...>" has an established meaning in Swift today which is not what is expressed in the "<P1,P2,P3>" contained inside Any<P1, P2,P3>.
>
>> On May 26, 2016, at 7:11 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>> wrote:
>>
>>
>>> on Thu May 26 2016, Adrian Zubarev <swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>> wrote:
>>>
>>> There is great feedback going on here. I'd like to consider a few things here:
>>>
>>> * What if we name the whole thing `Existential<>` to sort out all
>>> confusion?
>>
>> Some of us believe that “existential” is way too theoretical a word to
>> force into the official lexicon of Swift. I think “Any<...>” is much
>> more conceptually accessible.
>>
>>>
>>> This would allow `typealias Any = Existential<>`. * Should
>>> `protocol A: Any<class>` replace `protocol A: class`? Or at least
>>> deprecate it. * Do we need `typealias AnyClass = Any<class>` or do we
>>> want to use any class requirement existential directly? If second, we
>>> will need to allow direct existential usage on protocols (right now we
>>> only can use typealiases as a worksround).
>>
>> --
>> Dave
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto: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> <mailto: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> <mailto: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> <mailto: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 <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

From the point of view of the type system `P & Q` is an anonymous supertype of `P` and `Q`.
This would be just the same if the syntax was `Any<P, Q>`. I don’t see a semantic difference here.

Whether that is a "container“ or not seems to be an implementation detail to me but should have nothing to do with the type system.
In what way should it be "lossy“?

what is by definition lossy, is the relationship between a type and an existential type that can represent it. Comes from the fact that there is no way to go back to the type we started from once all we hold is the existential (i.e. means it is a one —> n mapping relationship, not a 1 —> 1). Not the notation.
right?

Am I missing something?

I was a bit confused as well and had to read this several times. I think this is talking about a syntactic “container” - i.e. brackets of some kind (as opposed to a “free floating” syntax). I don’t think it is talking about a semantic difference of any kind. But maybe I am still confused an not understanding what was intended...

given the semantic we wish to express (combination of conformance declarations), what possible ways do we have to express it. It come down to 2 families of syntax: the ‘container’ form, of which I gave a few examples, versus the non-container form (or free-floating conformance list) of which the straight list is the most obvious, but not the only one.

Joe Groff was reminding us that the second group of syntax also exists.

Compilers love Any<P...Q> , people’s brains love P & Q

-Thorsten

It seem to me we are debating the how of a what that has not been defined. The root question behind all these alternatives seems to be to decide if the existential-ness should be carried by a 'container' that is then refined internally, or derived from the presence of the free-floating refinements. This is the question that splits the possible syntaxes into these 2 groups:

Any<> Any
Type<> Type<>

this was meant to read
Type<…> Type { …. } Type[ … ]

···

On May 27, 2016, at 4:52 PM, Matthew Johnson <matthew@anandabits.com> wrote:

On May 27, 2016, at 7:20 AM, Thorsten Seitz via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Am 27.05.2016 um 12:30 schrieb L. Mihalkovic <laurent.mihalkovic@gmail.com <mailto:laurent.mihalkovic@gmail.com>>:

Existential<>

and the (these are all straw man representations that should not limit the thinking)

P & Q
@P and @Q
is P , Q
P & Q typed

If the answer is to use a 'container' then the next question is to see its relationship to the other existing containers: is it the result of a transformation, is it a superset, or a super type; it is obviously lossy, but not entirely if the solution follows in some of Brent's past suggestion to make some existential types instantiate-able (which opens a very similar problem to what java faced for several years when trying to identify a universal collection literal syntax).
That will narrow down the field of possible matches... until one syntax emerges as conveying the meaning that is reflected by the answers to each question.

On May 27, 2016, at 10:55 AM, Thorsten Seitz via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

We could just write

let x: P & Q
instead of
let x: Any<P, Q>

let x: Collection where .Element: P
instead of
let x: Any<Collection where .Element: P>

let x: P & Q where P.T == Q.T
instead of
let x: Any<P, Q where P.T == Q.T>

let x: P & Q & R
instead of
let x: Any<P, Q, R>

let x: Collection
instead of
let x: Any<Collection>

This would avoid the confusion of Any<T1, T2> being something completely different than a generic type (i.e. order of T1, T2 does not matter whereas for generic types it is essential).

-Thorsten

Am 26.05.2016 um 20:11 schrieb Adrian Zubarev via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

Something like type<…> was considered at the very start of the whole discussion (in this thread <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160502/016523.html&gt;\), but it does not solve the meaning of an existential type and also might lead to even more confusion.

From my perspective I wouldn’t use parentheses here because it looks more like an init without any label Type.init(…) or Type(…). I could live with Any[…] but this doesn’t look shiny and Swifty to me. Thats only my personal view. ;)

--
Adrian Zubarev
Sent with Airmail

Am 26. Mai 2016 bei 19:48:04, Vladimir.S via swift-evolution (swift-evolution@swift.org <mailto:swift-evolution@swift.org>) schrieb:

Don't think {} is better here, as they also have "established meaning in
Swift today".

How about just Type(P1 & P2 | P3) - as IMO we can think of such
construction as "creation" of new type and `P1 & P2 | P3` could be treated
as parameters to initializer.

func f(t: Type(P1 & P2 | P3)) {..}

On 26.05.2016 20:32, L. Mihalkovic via swift-evolution wrote:
> How about something like Type{P1 & P2 | P3} the point being that "<...>" has an established meaning in Swift today which is not what is expressed in the "<P1,P2,P3>" contained inside Any<P1, P2,P3>.
>
>> On May 26, 2016, at 7:11 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>
>>
>>> on Thu May 26 2016, Adrian Zubarev <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>
>>> There is great feedback going on here. I'd like to consider a few things here:
>>>
>>> * What if we name the whole thing `Existential<>` to sort out all
>>> confusion?
>>
>> Some of us believe that “existential” is way too theoretical a word to
>> force into the official lexicon of Swift. I think “Any<...>” is much
>> more conceptually accessible.
>>
>>>
>>> This would allow `typealias Any = Existential<>`. * Should
>>> `protocol A: Any<class>` replace `protocol A: class`? Or at least
>>> deprecate it. * Do we need `typealias AnyClass = Any<class>` or do we
>>> want to use any class requirement existential directly? If second, we
>>> will need to allow direct existential usage on protocols (right now we
>>> only can use typealiases as a worksround).
>>
>> --
>> Dave
>>
>> _______________________________________________
>> 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 <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 <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

Sent from my iPad

Here's a strawman idea.

What if we go with '&' and 'where', but we enclose the whole thing in parentheses?

(class & Protocol1 & Protocol2 where .Foo == Int, .Bar : Baz)

There are a couple of reasons I propose this syntax:

- It makes it very clear where the definition of the type begins and ends. I understand people really despise angle brackets, but I really want some way to visually delineate the boundaries of the type. Plus, I imagine it makes syntax a little easier to parse and preemptively forbids some ambiguities.

- It's a structural, not nominal, type, like a tuple, so it uses parens as well. This reserves "<" and ">" for generic types.

- The '&' is easily understood - "Protocol1" *and* "Protocol2". It's also a signal that order doesn't matter - just like how order matters with things that use commas, like argument lists, tuples, and array members, order doesn't generally matter with bitwise or logical 'and' operators.

- If we ever decide to have union types, we have a very elegant third form of nominal type syntax that naturally falls out: (MyClass1 | MyClass2 | MyClass3).

Thoughts?

Generally in favor. But I would not require the parentheses. I believe they would be allowed optionally automatically, just as (Int) is the same as Int (because single element tuples don't exist and the underlying type is used directly instead). It seems better to leave parentheses up to a matter of style.

Totally agree. Parentheses should only be required to resolve ambiguities.

-Thorsten

···

Am 27.05.2016 um 18:28 schrieb Matthew Johnson <matthew@anandabits.com>:
On May 27, 2016, at 11:18 AM, Austin Zheng <austinzheng@gmail.com <mailto:austinzheng@gmail.com>> wrote:

Austin

On May 27, 2016, at 9:07 AM, Thorsten Seitz via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Am 27.05.2016 um 16:54 schrieb Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>>:

On May 27, 2016, at 8:18 AM, Thorsten Seitz via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Personally I think `&` is more lightweight (and it is established in other languages like Ceylon and Typescript) and `where` is more expressive (and established in Swift for introducing constraints), so I would stay with these.

I agree. If we can make `&` with `where` work syntactically it would be nice to go in this lighter weight direction. If we decide to do that the question then becomes what to do with `protocol`. Would it be feasible to replace it with `&` in Swift 3 if we decide on that direction?

Yep. `protocol` should be replaced with `&` in that case.

-Thorsten

-Thorsten

Am 27.05.2016 um 14:34 schrieb Vladimir.S <svabox@gmail.com <mailto:svabox@gmail.com>>:

Btw, in case we have `where` keyword in syntax related to types/protocols (when defining constrains. and not some symbol like '>>'.. don't know, for example), why we can't have 'and' keyword also when discuss the syntax of type/protocol conjunction?
I.e.

let x: P and Q
let x: P and Q where P.T == Q.T
let x: P and Q and R

or, for consistency, as I understand it, we should have
let x: P & Q >> P.T == Q.T

On 27.05.2016 11:55, Thorsten Seitz via swift-evolution wrote:

We could just write

let x: P & Q
instead of
let x: Any<P, Q>

let x: Collection where .Element: P
instead of
let x: Any<Collection where .Element: P>

let x: P & Q where P.T == Q.T
instead of
let x: Any<P, Q where P.T == Q.T>

let x: P & Q & R
instead of
let x: Any<P, Q, R>

let x: Collection
instead of
let x: Any<Collection>

This would avoid the confusion of Any<T1, T2> being something completely
different than a generic type (i.e. order of T1, T2 does not matter whereas
for generic types it is essential).

-Thorsten

Am 26.05.2016 um 20:11 schrieb Adrian Zubarev via swift-evolution
<swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>>:

Something like |type<…>| was considered at the very start of the whole
discussion (in this thread
<https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160502/016523.html&gt;\),
but it does not solve the meaning of an existential type and also might
lead to even more confusion.

From my perspective I wouldn’t use parentheses here because it looks more
like an init without any label |Type.init(…)| or |Type(…)|. I could live
with |Any[…]| but this doesn’t look shiny and Swifty to me. Thats only my
personal view. ;)

--
Adrian Zubarev
Sent with Airmail

Am 26. Mai 2016 bei 19:48:04, Vladimir.S via swift-evolution
(swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>) schrieb:

Don't think {} is better here, as they also have "established meaning in
Swift today".

How about just Type(P1 & P2 | P3) - as IMO we can think of such
construction as "creation" of new type and `P1 & P2 | P3` could be treated
as parameters to initializer.

func f(t: Type(P1 & P2 | P3)) {..}

On 26.05.2016 20:32, L. Mihalkovic via swift-evolution wrote:
> How about something like Type{P1 & P2 | P3} the point being that "<...>" has an established meaning in Swift today which is not what is expressed in the "<P1,P2,P3>" contained inside Any<P1, P2,P3>.
>
>> On May 26, 2016, at 7:11 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>> wrote:
>>
>>
>>> on Thu May 26 2016, Adrian Zubarev <swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>> wrote:
>>>
>>> There is great feedback going on here. I'd like to consider a few things here:
>>>
>>> * What if we name the whole thing `Existential<>` to sort out all
>>> confusion?
>>
>> Some of us believe that “existential” is way too theoretical a word to
>> force into the official lexicon of Swift. I think “Any<...>” is much
>> more conceptually accessible.
>>
>>>
>>> This would allow `typealias Any = Existential<>`. * Should
>>> `protocol A: Any<class>` replace `protocol A: class`? Or at least
>>> deprecate it. * Do we need `typealias AnyClass = Any<class>` or do we
>>> want to use any class requirement existential directly? If second, we
>>> will need to allow direct existential usage on protocols (right now we
>>> only can use typealiases as a worksround).
>>
>> --
>> Dave
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto: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> <mailto: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> <mailto: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> <mailto: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 <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

I think the parentheses are the fundamental aspect of the suggestion :).

Let me turn the question around. If tuples were declared like this:

let myTuple : Int, String, Bool = (10, "hello", false)

would the type be more or less readable? I find it a lot more difficult to immediately parse than:

let myTuple : (Int, String, Bool) = (10, "hello", false)

At the same time, nobody's complained about tuple type parentheses getting in the way.

Parentheses are the hallmark of tuples, so its natural to expect them around the tuple type as well :-)

We're trying to establish a syntax that will hopefully be used for things significantly more complicated than tuple definitions, which are just a list of types. I think readability is a major concern. Typealiases should be supported, but they shouldn't be required to make the feature useable.

Finally, wouldn't we need some delimiter for nested existential definitions anyways? Now you have the confusing situation where the outside definition has no delimiters, but the inside ones do:

Why is this confusing? The expression `2 * (3 + 1)` also has parentheses only around the part which needs them.
Probably no one would require having to write `(2 * (3 + 1))` for consistency.

// Why does the inner existential look fundamentally different than the outer one?
// Not to mention, visually parsing the boundaries of this type when you look at it in a function signature
let x : Protocol1, Protocol2, (Protocol 3 where .Foo == Int) where Protocol2.Bar : Baz

Using `&` instead of `,` will make it look better, too, IMHO:

let x: Protocol1 & Protocol2 & (Protocol3 where .Foo == Int) where Protocol2.Bar: Baz

or better (removing the asymmetry):

let x: Protocol1 & (Protocol2 where .Bar : Baz) & (Protocol3 where .Foo == Int)

or putting all constraints in the where clause for the whole expression:

let x: Protocol1 & Protocol2 & Protocol3 where Protocol2.Bar: Baz, Protocol3.Foo == Int

-Thorsten

···

Am 27.05.2016 um 18:36 schrieb Austin Zheng <austinzheng@gmail.com>:

I hope that explains my reasoning.

Best,
Austin

On May 27, 2016, at 9:28 AM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

Sent from my iPad

On May 27, 2016, at 11:18 AM, Austin Zheng <austinzheng@gmail.com <mailto:austinzheng@gmail.com>> wrote:

Here's a strawman idea.

What if we go with '&' and 'where', but we enclose the whole thing in parentheses?

(class & Protocol1 & Protocol2 where .Foo == Int, .Bar : Baz)

There are a couple of reasons I propose this syntax:

- It makes it very clear where the definition of the type begins and ends. I understand people really despise angle brackets, but I really want some way to visually delineate the boundaries of the type. Plus, I imagine it makes syntax a little easier to parse and preemptively forbids some ambiguities.

- It's a structural, not nominal, type, like a tuple, so it uses parens as well. This reserves "<" and ">" for generic types.

- The '&' is easily understood - "Protocol1" *and* "Protocol2". It's also a signal that order doesn't matter - just like how order matters with things that use commas, like argument lists, tuples, and array members, order doesn't generally matter with bitwise or logical 'and' operators.

- If we ever decide to have union types, we have a very elegant third form of nominal type syntax that naturally falls out: (MyClass1 | MyClass2 | MyClass3).

Thoughts?

Generally in favor. But I would not require the parentheses. I believe they would be allowed optionally automatically, just as (Int) is the same as Int (because single element tuples don't exist and the underlying type is used directly instead). It seems better to leave parentheses up to a matter of style.

Austin

On May 27, 2016, at 9:07 AM, Thorsten Seitz via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Am 27.05.2016 um 16:54 schrieb Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>>:

On May 27, 2016, at 8:18 AM, Thorsten Seitz via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Personally I think `&` is more lightweight (and it is established in other languages like Ceylon and Typescript) and `where` is more expressive (and established in Swift for introducing constraints), so I would stay with these.

I agree. If we can make `&` with `where` work syntactically it would be nice to go in this lighter weight direction. If we decide to do that the question then becomes what to do with `protocol`. Would it be feasible to replace it with `&` in Swift 3 if we decide on that direction?

Yep. `protocol` should be replaced with `&` in that case.

-Thorsten

-Thorsten

Am 27.05.2016 um 14:34 schrieb Vladimir.S <svabox@gmail.com <mailto:svabox@gmail.com>>:

Btw, in case we have `where` keyword in syntax related to types/protocols (when defining constrains. and not some symbol like '>>'.. don't know, for example), why we can't have 'and' keyword also when discuss the syntax of type/protocol conjunction?
I.e.

let x: P and Q
let x: P and Q where P.T == Q.T
let x: P and Q and R

or, for consistency, as I understand it, we should have
let x: P & Q >> P.T == Q.T

On 27.05.2016 11:55, Thorsten Seitz via swift-evolution wrote:

We could just write

let x: P & Q
instead of
let x: Any<P, Q>

let x: Collection where .Element: P
instead of
let x: Any<Collection where .Element: P>

let x: P & Q where P.T == Q.T
instead of
let x: Any<P, Q where P.T == Q.T>

let x: P & Q & R
instead of
let x: Any<P, Q, R>

let x: Collection
instead of
let x: Any<Collection>

This would avoid the confusion of Any<T1, T2> being something completely
different than a generic type (i.e. order of T1, T2 does not matter whereas
for generic types it is essential).

-Thorsten

Am 26.05.2016 um 20:11 schrieb Adrian Zubarev via swift-evolution
<swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>>:

Something like |type<…>| was considered at the very start of the whole
discussion (in this thread
<https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160502/016523.html&gt;\),
but it does not solve the meaning of an existential type and also might
lead to even more confusion.

From my perspective I wouldn’t use parentheses here because it looks more
like an init without any label |Type.init(…)| or |Type(…)|. I could live
with |Any[…]| but this doesn’t look shiny and Swifty to me. Thats only my
personal view. ;)

--
Adrian Zubarev
Sent with Airmail

Am 26. Mai 2016 bei 19:48:04, Vladimir.S via swift-evolution
(swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>) schrieb:

Don't think {} is better here, as they also have "established meaning in
Swift today".

How about just Type(P1 & P2 | P3) - as IMO we can think of such
construction as "creation" of new type and `P1 & P2 | P3` could be treated
as parameters to initializer.

func f(t: Type(P1 & P2 | P3)) {..}

On 26.05.2016 20:32, L. Mihalkovic via swift-evolution wrote:
> How about something like Type{P1 & P2 | P3} the point being that "<...>" has an established meaning in Swift today which is not what is expressed in the "<P1,P2,P3>" contained inside Any<P1, P2,P3>.
>
>> On May 26, 2016, at 7:11 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>> wrote:
>>
>>
>>> on Thu May 26 2016, Adrian Zubarev <swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>> wrote:
>>>
>>> There is great feedback going on here. I'd like to consider a few things here:
>>>
>>> * What if we name the whole thing `Existential<>` to sort out all
>>> confusion?
>>
>> Some of us believe that “existential” is way too theoretical a word to
>> force into the official lexicon of Swift. I think “Any<...>” is much
>> more conceptually accessible.
>>
>>>
>>> This would allow `typealias Any = Existential<>`. * Should
>>> `protocol A: Any<class>` replace `protocol A: class`? Or at least
>>> deprecate it. * Do we need `typealias AnyClass = Any<class>` or do we
>>> want to use any class requirement existential directly? If second, we
>>> will need to allow direct existential usage on protocols (right now we
>>> only can use typealiases as a worksround).
>>
>> --
>> Dave
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto: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> <mailto: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> <mailto: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> <mailto: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 <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

For me requiring parentheses for this 'feature' will confuse in most cases as looks similar to tuple definition:

let x : (Int, String, Bool) = oneThing
let y : (MyProto & Hashable) = anotherThing

but below looks IMO more clean and I instantly(don't need to parse first open parenthesis) see that this is a 'conjunction' of protocols not tuple :

let y : MyProto & Hashable = anotherThing

Bur +1 for optional parentheses

···

On 27.05.2016 19:36, Austin Zheng via swift-evolution wrote:

I think the parentheses are the fundamental aspect of the suggestion :).

Let me turn the question around. If tuples were declared like this:

let myTuple : Int, String, Bool = (10, "hello", false)

would the type be more or less readable? I find it a lot more difficult to
immediately parse than:

let myTuple : (Int, String, Bool) = (10, "hello", false)

At the same time, nobody's complained about tuple type parentheses getting
in the way.

We're trying to establish a syntax that will hopefully be used for things
significantly more complicated than tuple definitions, which are just a
list of types. I think readability is a major concern. Typealiases should
be supported, but they shouldn't be required to make the feature useable.

Finally, wouldn't we need some delimiter for nested existential definitions
anyways? Now you have the confusing situation where the outside definition
has no delimiters, but the inside ones do:

// Why does the inner existential look fundamentally different than the
outer one?
// Not to mention, visually parsing the boundaries of this type when you
look at it in a function signature
let x : Protocol1, Protocol2, (Protocol 3 where .Foo == Int) where
Protocol2.Bar : Baz

I hope that explains my reasoning.

Best,
Austin

On May 27, 2016, at 9:28 AM, Matthew Johnson <matthew@anandabits.com >> <mailto:matthew@anandabits.com>> wrote:

Sent from my iPad

On May 27, 2016, at 11:18 AM, Austin Zheng <austinzheng@gmail.com >> <mailto:austinzheng@gmail.com>> wrote:

Here's a strawman idea.

What if we go with '&' and 'where', but we enclose the whole thing in
parentheses?

(class & Protocol1 & Protocol2 where .Foo == Int, .Bar : Baz)

There are a couple of reasons I propose this syntax:

- It makes it very clear where the definition of the type begins and
ends. I understand people really despise angle brackets, but I really
want some way to visually delineate the boundaries of the type. Plus, I
imagine it makes syntax a little easier to parse and preemptively
forbids some ambiguities.

- It's a structural, not nominal, type, like a tuple, so it uses parens
as well. This reserves "<" and ">" for generic types.

- The '&' is easily understood - "Protocol1" *and* "Protocol2". It's
also a signal that order doesn't matter - just like how order matters
with things that use commas, like argument lists, tuples, and array
members, order doesn't generally matter with bitwise or logical 'and'
operators.

- If we ever decide to have union types, we have a very elegant third
form of nominal type syntax that naturally falls out: (MyClass1 |
MyClass2 | MyClass3).

Thoughts?

Generally in favor. But I would not require the parentheses. I believe
they would be allowed optionally automatically, just as (Int) is the same
as Int (because single element tuples don't exist and the underlying type
is used directly instead). It seems better to leave parentheses up to a
matter of style.

Austin

On May 27, 2016, at 9:07 AM, Thorsten Seitz via swift-evolution >>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Am 27.05.2016 um 16:54 schrieb Matthew Johnson <matthew@anandabits.com
<mailto:matthew@anandabits.com>>:

On May 27, 2016, at 8:18 AM, Thorsten Seitz via swift-evolution >>>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Personally I think `&` is more lightweight (and it is established in
other languages like Ceylon and Typescript) and `where` is more
expressive (and established in Swift for introducing constraints), so
I would stay with these.

I agree. If we can make `&` with `where` work syntactically it would
be nice to go in this lighter weight direction. If we decide to do
that the question then becomes what to do with `protocol`. Would it
be feasible to replace it with `&` in Swift 3 if we decide on that
direction?

Yep. `protocol` should be replaced with `&` in that case.

-Thorsten

-Thorsten

Am 27.05.2016 um 14:34 schrieb Vladimir.S <svabox@gmail.com
<mailto:svabox@gmail.com>>:

Btw, in case we have `where` keyword in syntax related to
types/protocols (when defining constrains. and not some symbol like
'>>'.. don't know, for example), why we can't have 'and' keyword
also when discuss the syntax of type/protocol conjunction?
I.e.

let x: P and Q
let x: P and Q where P.T == Q.T
let x: P and Q and R

or, for consistency, as I understand it, we should have
let x: P & Q >> P.T == Q.T

On 27.05.2016 11:55, Thorsten Seitz via swift-evolution wrote:

We could just write

let x: P & Q
instead of
let x: Any<P, Q>

let x: Collection where .Element: P
instead of
let x: Any<Collection where .Element: P>

let x: P & Q where P.T == Q.T
instead of
let x: Any<P, Q where P.T == Q.T>

let x: P & Q & R
instead of
let x: Any<P, Q, R>

let x: Collection
instead of
let x: Any<Collection>

This would avoid the confusion of Any<T1, T2> being something
completely
different than a generic type (i.e. order of T1, T2 does not matter
whereas
for generic types it is essential).

-Thorsten

Am 26.05.2016 um 20:11 schrieb Adrian Zubarev via swift-evolution >>>>>>>>> <swift-evolution@swift.org
<mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org>>:

Something like |type<…>| was considered at the very start of the whole
discussion (in this thread
<https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160502/016523.html&gt;\),
but it does not solve the meaning of an existential type and also
might
lead to even more confusion.

From my perspective I wouldn’t use parentheses here because it
looks more
like an init without any label |Type.init(…)| or |Type(…)|. I
could live
with |Any[…]| but this doesn’t look shiny and Swifty to me. Thats
only my
personal view. ;)

--
Adrian Zubarev
Sent with Airmail

Am 26. Mai 2016 bei 19:48:04, Vladimir.S via swift-evolution
(swift-evolution@swift.org
<mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org>)
schrieb:

Don't think {} is better here, as they also have "established
meaning in
Swift today".

How about just Type(P1 & P2 | P3) - as IMO we can think of such
construction as "creation" of new type and `P1 & P2 | P3` could
be treated
as parameters to initializer.

func f(t: Type(P1 & P2 | P3)) {..}

On 26.05.2016 20:32, L. Mihalkovic via swift-evolution wrote:
> How about something like Type{P1 & P2 | P3} the point being
that "<...>" has an established meaning in Swift today which is
not what is expressed in the "<P1,P2,P3>" contained inside
Any<P1, P2,P3>.
>
>> On May 26, 2016, at 7:11 PM, Dave Abrahams via swift-evolution >>>>>>>>>> <swift-evolution@swift.org >>>>>>>>>> <mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org>> >>>>>>>>>> wrote:
>>
>>> on Thu May 26 2016, Adrian Zubarev <swift-evolution@swift.org >>>>>>>>>> <mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org>> >>>>>>>>>> wrote:
>>>
>>> There is great feedback going on here. I'd like to consider a
few things here:
>>>
>>> * What if we name the whole thing `Existential<>` to sort out all
>>> confusion?
>>
>> Some of us believe that “existential” is way too theoretical a
word to
>> force into the official lexicon of Swift. I think “Any<...>”
is much
>> more conceptually accessible.
>>
>>>
>>> This would allow `typealias Any = Existential<>`. * Should
>>> `protocol A: Any<class>` replace `protocol A: class`? Or at least
>>> deprecate it. * Do we need `typealias AnyClass = Any<class>`
or do we
>>> want to use any class requirement existential directly? If
second, we
>>> will need to allow direct existential usage on protocols
(right now we
>>> only can use typealiases as a worksround).
>>
>> --
>> Dave
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org
<mailto: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> <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> <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> <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 <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

Thanks for all your thoughtful replies.

I'm not really invested in arguing this much further, as it's mainly a stylistic thing that I could live with and also probably a hopeless battle (given how everyone else disagrees).

I’ve been in the same place with some of the other stylistic battles. :-)

But I would like to address a few final points.

(inline)

Turning it around, we don’t have to put parentheses around function types and nobody complains about it being problematic even for higher-order functions with several steps before the final result.

Function types have a very regular syntax, especially now that 0066 was accepted (which, I admit, was very controversal itself):

( <one or more types> ) -> (tuple)
or
( <one or more types> ) -> SingleTypeWithNoSpaces
or
( <one or more types> ) -> GenericType<All, Spaces, Are, Inside, The, Brackets>

A function type is very easy to visually parse: combine the argument parens, arrow thing, and the single type that it returns. That being said, complex function types are probably the most difficult types to read in a function declaration today, even with this regular structure.

The proposed syntax, which allows arbitrary whitespace outside the context of a delimiter, would require the user to scan the string comprising the existential type expression for a very common sigil in order to locate the endpoint: '=' for variable declarations (which admittedly isn't that bad) or ',' for functions (which is a lot worse). Not to mention the point Joe Groff brought up about a generic function with a generic where clause returning an existential and having everything devolve into a undifferentiated soup of identifiers.

Does anyone know if users of Ceylon or other languages with the unparenthesized syntax find it problematic? How would they feel about being required to use parentheses?

We're trying to establish a syntax that will hopefully be used for things significantly more complicated than tuple definitions, which are just a list of types. I think readability is a major concern. Typealiases should be supported, but they shouldn't be required to make the feature useable.

I agree, but I don’t think they would be required to make the feature useable just because parentheses are not required. If a developer or team thinks they are required for clarity / readability, etc they are free to use them. This is a style issue that should be addressed by a linter, not the formal syntax of the language.

It is a style issue, but so is (Int) -> T versus Int -> T and a lot of other language details like trailing commas in argument lists, of which the core team seems to feel pretty strongly about.

Fair enough! :-)

Finally, wouldn't we need some delimiter for nested existential definitions anyways? Now you have the confusing situation where the outside definition has no delimiters, but the inside ones do:

// Why does the inner existential look fundamentally different than the outer one?
// Not to mention, visually parsing the boundaries of this type when you look at it in a function signature
let x : Protocol1, Protocol2, (Protocol 3 where .Foo == Int) where Protocol2.Bar : Baz

Nested existentials are supported not because it would ever be a good idea to actually write them. They are supported to allow composition of existentials:

Perhaps then we should only allow existentials to be nested if a typealias is used. Swift is, after all, an opinionated language. If a feature is in the language, it should either be usable directly in an ergonomic way, or it shouldn't be there at all. Having a self-admittedly "bad" way to nest literal existential expressions just for consistency when typealiases are the preferred use case is very unlike Swift.

I think self-admittedly “bad” is a bit of a stretch. I do *think* the conventional style would be to match the rest of Swift. But I’m not *certain* of that. I could see the style Thorsten posted being conventional and useful in some cases:

let x : Protocol1 & (Protocol2 where .Bar : Baz) & (Protocol 3 where .Foo == Int)

I think direct `&` syntax will be most useful when combining two (or maybe three) protocols with no associated types: `Protocol1 & Protocol2` (whether or not we require parens).

Generally I hope we will use type aliases for existentials that are this complex just as we usually bind names to parts of expressions rather than writing large one-liners.

One issue I’m not sure we have addressed is the case of an existential for a single protocol with an associated type constraint `Protocol where .Foo = Int`. Before we settle on a syntax we should be sure that this doesn’t introduce any ambiguity.

Austin raised the point (or reminded of Joe’s raising the point) of possible problems when returning constrained existentials from generic functions:

func foo<P, Q>(p: P, q: Q) -> any<Collection where .Element == P> where P: Equatable { … }

would require parentheses when using `&` instead of any<>

func foo<P, Q>(p: P, q: Q) -> (Collection where .Element == P) where P: Equatable { … }

This would even be the case if there was no constraint on P:

func foo<P, Q>(p: P, q: Q) -> (Collection where .Element == P) { … }

An alternative would be to use `with` for existentials instead of `where`:

func foo<P, Q>(p: P, q: Q) -> Collection with .Element == P where P: Equatable { … }

But even then this would be more readable either with parentheses (now just as a matter of style) or a line break:

func foo<P, Q>(p: P, q: Q) -> Collection with .Element == P
  where P: Equatable { … }

-Thorsten

···

Am 27.05.2016 um 21:41 schrieb Matthew Johnson <matthew@anandabits.com>:

On May 27, 2016, at 2:26 PM, Austin Zheng <austinzheng@gmail.com <mailto:austinzheng@gmail.com>> wrote:
On Fri, May 27, 2016 at 12:06 PM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

-Matthew

typealias P3Int = Protocol 3 where .Foo == Int
let x : Protocol1, Protocol2, P3Int where Protocol2.Bar : Baz

If you are writing the entire type in a single location I expect the conventional style to be like this:

let x : Protocol1, Protocol2, Protocol 3 where Protocol2.Bar : Baz, Protocol3.Foo == Int

With all associated types constraints in a single `where` clause as we other places they are written in Swift.

Maybe I am wrong about that and a different conventional style would emerge (for example, where clauses clustered with the related protocol).

But *requiring* parentheses is really orthogonal to the style issue of where and when it is considered *advisable* to use them.

-Matthew

I hope that explains my reasoning.

Best,
Austin

On May 27, 2016, at 9:28 AM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

Sent from my iPad

On May 27, 2016, at 11:18 AM, Austin Zheng <austinzheng@gmail.com <mailto:austinzheng@gmail.com>> wrote:

Here's a strawman idea.

What if we go with '&' and 'where', but we enclose the whole thing in parentheses?

(class & Protocol1 & Protocol2 where .Foo == Int, .Bar : Baz)

There are a couple of reasons I propose this syntax:

- It makes it very clear where the definition of the type begins and ends. I understand people really despise angle brackets, but I really want some way to visually delineate the boundaries of the type. Plus, I imagine it makes syntax a little easier to parse and preemptively forbids some ambiguities.

- It's a structural, not nominal, type, like a tuple, so it uses parens as well. This reserves "<" and ">" for generic types.

- The '&' is easily understood - "Protocol1" *and* "Protocol2". It's also a signal that order doesn't matter - just like how order matters with things that use commas, like argument lists, tuples, and array members, order doesn't generally matter with bitwise or logical 'and' operators.

- If we ever decide to have union types, we have a very elegant third form of nominal type syntax that naturally falls out: (MyClass1 | MyClass2 | MyClass3).

Thoughts?

Generally in favor. But I would not require the parentheses. I believe they would be allowed optionally automatically, just as (Int) is the same as Int (because single element tuples don't exist and the underlying type is used directly instead). It seems better to leave parentheses up to a matter of style.

Austin

On May 27, 2016, at 9:07 AM, Thorsten Seitz via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Am 27.05.2016 um 16:54 schrieb Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>>:

On May 27, 2016, at 8:18 AM, Thorsten Seitz via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Personally I think `&` is more lightweight (and it is established in other languages like Ceylon and Typescript) and `where` is more expressive (and established in Swift for introducing constraints), so I would stay with these.

I agree. If we can make `&` with `where` work syntactically it would be nice to go in this lighter weight direction. If we decide to do that the question then becomes what to do with `protocol`. Would it be feasible to replace it with `&` in Swift 3 if we decide on that direction?

Yep. `protocol` should be replaced with `&` in that case.

-Thorsten

-Thorsten

Am 27.05.2016 um 14:34 schrieb Vladimir.S <svabox@gmail.com <mailto:svabox@gmail.com>>:

Btw, in case we have `where` keyword in syntax related to types/protocols (when defining constrains. and not some symbol like '>>'.. don't know, for example), why we can't have 'and' keyword also when discuss the syntax of type/protocol conjunction?
I.e.

let x: P and Q
let x: P and Q where P.T == Q.T
let x: P and Q and R

or, for consistency, as I understand it, we should have
let x: P & Q >> P.T == Q.T

On 27.05.2016 11:55, Thorsten Seitz via swift-evolution wrote:

We could just write

let x: P & Q
instead of
let x: Any<P, Q>

let x: Collection where .Element: P
instead of
let x: Any<Collection where .Element: P>

let x: P & Q where P.T == Q.T
instead of
let x: Any<P, Q where P.T == Q.T>

let x: P & Q & R
instead of
let x: Any<P, Q, R>

let x: Collection
instead of
let x: Any<Collection>

This would avoid the confusion of Any<T1, T2> being something completely
different than a generic type (i.e. order of T1, T2 does not matter whereas
for generic types it is essential).

-Thorsten

Am 26.05.2016 um 20:11 schrieb Adrian Zubarev via swift-evolution
<swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>>:

Something like |type<…>| was considered at the very start of the whole
discussion (in this thread
<https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160502/016523.html&gt;\),
but it does not solve the meaning of an existential type and also might
lead to even more confusion.

From my perspective I wouldn’t use parentheses here because it looks more
like an init without any label |Type.init(…)| or |Type(…)|. I could live
with |Any[…]| but this doesn’t look shiny and Swifty to me. Thats only my
personal view. ;)

--
Adrian Zubarev
Sent with Airmail

Am 26. Mai 2016 bei 19:48:04, Vladimir.S via swift-evolution
(swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>) schrieb:

Don't think {} is better here, as they also have "established meaning in
Swift today".

How about just Type(P1 & P2 | P3) - as IMO we can think of such
construction as "creation" of new type and `P1 & P2 | P3` could be treated
as parameters to initializer.

func f(t: Type(P1 & P2 | P3)) {..}

On 26.05.2016 20:32, L. Mihalkovic via swift-evolution wrote:
> How about something like Type{P1 & P2 | P3} the point being that "<...>" has an established meaning in Swift today which is not what is expressed in the "<P1,P2,P3>" contained inside Any<P1, P2,P3>.
>
>> On May 26, 2016, at 7:11 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>> wrote:
>>
>>
>>> on Thu May 26 2016, Adrian Zubarev <swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>> wrote:
>>>
>>> There is great feedback going on here. I'd like to consider a few things here:
>>>
>>> * What if we name the whole thing `Existential<>` to sort out all
>>> confusion?
>>
>> Some of us believe that “existential” is way too theoretical a word to
>> force into the official lexicon of Swift. I think “Any<...>” is much
>> more conceptually accessible.
>>
>>>
>>> This would allow `typealias Any = Existential<>`. * Should
>>> `protocol A: Any<class>` replace `protocol A: class`? Or at least
>>> deprecate it. * Do we need `typealias AnyClass = Any<class>` or do we
>>> want to use any class requirement existential directly? If second, we
>>> will need to allow direct existential usage on protocols (right now we
>>> only can use typealiases as a worksround).
>>
>> --
>> Dave
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto: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> <mailto: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> <mailto: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> <mailto: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 <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

(inline)

I think the parentheses are the fundamental aspect of the suggestion :).

Let me turn the question around. If tuples were declared like this:

let myTuple : Int, String, Bool = (10, "hello", false)

would the type be more or less readable? I find it a lot more difficult to
immediately parse than:

let myTuple : (Int, String, Bool) = (10, "hello", false)

At the same time, nobody's complained about tuple type parentheses getting
in the way.

Parentheses are the hallmark of tuples, so its natural to expect them
around the tuple type as well :-)

But this is a circular definition. Why can't parentheses be the hallmark of
structural types, not just tuples? After all, one of the big complaints
against the Any<> and protocol<> syntaxes has been that angle brackets
belong to generics already.

We're trying to establish a syntax that will hopefully be used for things
significantly more complicated than tuple definitions, which are just a
list of types. I think readability is a major concern. Typealiases should
be supported, but they shouldn't be required to make the feature useable.

Finally, wouldn't we need some delimiter for nested existential
definitions anyways? Now you have the confusing situation where the outside
definition has no delimiters, but the inside ones do:

Why is this confusing? The expression `2 * (3 + 1)` also has parentheses
only around the part which needs them.
Probably no one would require having to write `(2 * (3 + 1))` for
consistency.

You can make the same argument about tuples.

// Why does the inner existential look fundamentally different than the
outer one?
// Not to mention, visually parsing the boundaries of this type when you
look at it in a function signature
let x : Protocol1, Protocol2, (Protocol 3 where .Foo == Int) where
Protocol2.Bar : Baz

Using `&` instead of `,` will make it look better, too, IMHO:

let x: Protocol1 & Protocol2 & (Protocol3 where .Foo == Int) where
Protocol2.Bar: Baz

I agree that '&' is better - my mistake. I still submit my concerns about
legibility.

or better (removing the asymmetry):

let x: Protocol1 & (Protocol2 where .Bar : Baz) & (Protocol3 where .Foo ==
Int)

or putting all constraints in the where clause for the whole expression:

let x: Protocol1 & Protocol2 & Protocol3 where Protocol2.Bar: Baz,
Protocol3.Foo == Int

I would much rather have parentheses enclosing the outside type than force
people to structure their requirements a certain way.

···

On Fri, May 27, 2016 at 10:09 AM, Thorsten Seitz <tseitz42@icloud.com> wrote:

Am 27.05.2016 um 18:36 schrieb Austin Zheng <austinzheng@gmail.com>:

-Thorsten

I hope that explains my reasoning.

Best,
Austin

On May 27, 2016, at 9:28 AM, Matthew Johnson <matthew@anandabits.com> > wrote:

Sent from my iPad

On May 27, 2016, at 11:18 AM, Austin Zheng <austinzheng@gmail.com> wrote:

Here's a strawman idea.

What if we go with '&' and 'where', but we enclose the whole thing in
parentheses?

(class & Protocol1 & Protocol2 where .Foo == Int, .Bar : Baz)

There are a couple of reasons I propose this syntax:

- It makes it very clear where the definition of the type begins and ends.
I understand people really despise angle brackets, but I really want some
way to visually delineate the boundaries of the type. Plus, I imagine it
makes syntax a little easier to parse and preemptively forbids some
ambiguities.

- It's a structural, not nominal, type, like a tuple, so it uses parens as
well. This reserves "<" and ">" for generic types.

- The '&' is easily understood - "Protocol1" *and* "Protocol2". It's also
a signal that order doesn't matter - just like how order matters with
things that use commas, like argument lists, tuples, and array members,
order doesn't generally matter with bitwise or logical 'and' operators.

- If we ever decide to have union types, we have a very elegant third form
of nominal type syntax that naturally falls out: (MyClass1 | MyClass2 |
MyClass3).

Thoughts?

Generally in favor. But I would not require the parentheses. I believe
they would be allowed optionally automatically, just as (Int) is the same
as Int (because single element tuples don't exist and the underlying type
is used directly instead). It seems better to leave parentheses up to a
matter of style.

Austin

On May 27, 2016, at 9:07 AM, Thorsten Seitz via swift-evolution < > swift-evolution@swift.org> wrote:

Am 27.05.2016 um 16:54 schrieb Matthew Johnson <matthew@anandabits.com>:

On May 27, 2016, at 8:18 AM, Thorsten Seitz via swift-evolution < > swift-evolution@swift.org> wrote:

Personally I think `&` is more lightweight (and it is established in other
languages like Ceylon and Typescript) and `where` is more expressive (and
established in Swift for introducing constraints), so I would stay with
these.

I agree. If we can make `&` with `where` work syntactically it would be
nice to go in this lighter weight direction. If we decide to do that the
question then becomes what to do with `protocol`. Would it be feasible to
replace it with `&` in Swift 3 if we decide on that direction?

Yep. `protocol` should be replaced with `&` in that case.

-Thorsten

-Thorsten

Am 27.05.2016 um 14:34 schrieb Vladimir.S <svabox@gmail.com>:

Btw, in case we have `where` keyword in syntax related to types/protocols
(when defining constrains. and not some symbol like '>>'.. don't know, for
example), why we can't have 'and' keyword also when discuss the syntax of
type/protocol conjunction?
I.e.

let x: P and Q
let x: P and Q where P.T == Q.T
let x: P and Q and R

or, for consistency, as I understand it, we should have
let x: P & Q >> P.T == Q.T

On 27.05.2016 11:55, Thorsten Seitz via swift-evolution wrote:

We could just write

let x: P & Q
instead of
let x: Any<P, Q>

let x: Collection where .Element: P
instead of
let x: Any<Collection where .Element: P>

let x: P & Q where P.T == Q.T
instead of
let x: Any<P, Q where P.T == Q.T>

let x: P & Q & R
instead of
let x: Any<P, Q, R>

let x: Collection
instead of
let x: Any<Collection>

This would avoid the confusion of Any<T1, T2> being something completely
different than a generic type (i.e. order of T1, T2 does not matter whereas
for generic types it is essential).

-Thorsten

Am 26.05.2016 um 20:11 schrieb Adrian Zubarev via swift-evolution
<swift-evolution@swift.org <mailto:swift-evolution@swift.org
<swift-evolution@swift.org>>>:

Something like |type<…>| was considered at the very start of the whole
discussion (in this thread
<
[swift-evolution] [Pitch] merge types and protocols back together with type<Type, Protocol, ...>
>),
but it does not solve the meaning of an existential type and also might
lead to even more confusion.

From my perspective I wouldn’t use parentheses here because it looks more
like an init without any label |Type.init(…)| or |Type(…)|. I could live
with |Any[…]| but this doesn’t look shiny and Swifty to me. Thats only my
personal view. ;)

--
Adrian Zubarev
Sent with Airmail

Am 26. Mai 2016 bei 19:48:04, Vladimir.S via swift-evolution
(swift-evolution@swift.org <mailto:swift-evolution@swift.org
<swift-evolution@swift.org>>) schrieb:

Don't think {} is better here, as they also have "established meaning in
Swift today".

How about just Type(P1 & P2 | P3) - as IMO we can think of such
construction as "creation" of new type and `P1 & P2 | P3` could be treated
as parameters to initializer.

func f(t: Type(P1 & P2 | P3)) {..}

On 26.05.2016 20:32, L. Mihalkovic via swift-evolution wrote:
> How about something like Type{P1 & P2 | P3} the point being that "<...>"
has an established meaning in Swift today which is not what is expressed in
the "<P1,P2,P3>" contained inside Any<P1, P2,P3>.
>
>> On May 26, 2016, at 7:11 PM, Dave Abrahams via swift-evolution < > swift-evolution@swift.org <mailto:swift-evolution@swift.org > <swift-evolution@swift.org>>> wrote:
>>
>>
>>> on Thu May 26 2016, Adrian Zubarev <swift-evolution@swift.org < > mailto:swift-evolution@swift.org <swift-evolution@swift.org>>> wrote:
>>>
>>> There is great feedback going on here. I'd like to consider a few
things here:
>>>
>>> * What if we name the whole thing `Existential<>` to sort out all
>>> confusion?
>>
>> Some of us believe that “existential” is way too theoretical a word to
>> force into the official lexicon of Swift. I think “Any<...>” is much
>> more conceptually accessible.
>>
>>>
>>> This would allow `typealias Any = Existential<>`. * Should
>>> `protocol A: Any<class>` replace `protocol A: class`? Or at least
>>> deprecate it. * Do we need `typealias AnyClass = Any<class>` or do we
>>> want to use any class requirement existential directly? If second, we
>>> will need to allow direct existential usage on protocols (right now we
>>> only can use typealiases as a worksround).
>>
>> --
>> Dave
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org <mailto:swift-evolution@swift.org
<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
<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
<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
<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

(inline)

I think the parentheses are the fundamental aspect of the suggestion :).

Let me turn the question around. If tuples were declared like this:

let myTuple : Int, String, Bool = (10, "hello", false)

would the type be more or less readable? I find it a lot more difficult to immediately parse than:

let myTuple : (Int, String, Bool) = (10, "hello", false)

At the same time, nobody's complained about tuple type parentheses getting in the way.

Parentheses are the hallmark of tuples, so its natural to expect them around the tuple type as well :-)

But this is a circular definition. Why can't parentheses be the hallmark of structural types, not just tuples? After all, one of the big complaints against the Any<> and protocol<> syntaxes has been that angle brackets belong to generics already.

They are not a hallmark of function types. We write `(Int) -> (Int) -> (Int) -> Int`, not `((Int) -> (Int) -> (Int) -> Int)`.

We're trying to establish a syntax that will hopefully be used for things significantly more complicated than tuple definitions, which are just a list of types. I think readability is a major concern. Typealiases should be supported, but they shouldn't be required to make the feature useable.

Finally, wouldn't we need some delimiter for nested existential definitions anyways? Now you have the confusing situation where the outside definition has no delimiters, but the inside ones do:

Why is this confusing? The expression `2 * (3 + 1)` also has parentheses only around the part which needs them.
Probably no one would require having to write `(2 * (3 + 1))` for consistency.

You can make the same argument about tuples.

// Why does the inner existential look fundamentally different than the outer one?
// Not to mention, visually parsing the boundaries of this type when you look at it in a function signature
let x : Protocol1, Protocol2, (Protocol 3 where .Foo == Int) where Protocol2.Bar : Baz

Using `&` instead of `,` will make it look better, too, IMHO:

let x: Protocol1 & Protocol2 & (Protocol3 where .Foo == Int) where Protocol2.Bar: Baz

I agree that '&' is better - my mistake. I still submit my concerns about legibility.

or better (removing the asymmetry):

let x: Protocol1 & (Protocol2 where .Bar : Baz) & (Protocol3 where .Foo == Int)

or putting all constraints in the where clause for the whole expression:

let x: Protocol1 & Protocol2 & Protocol3 where Protocol2.Bar: Baz, Protocol3.Foo == Int

I would much rather have parentheses enclosing the outside type than force people to structure their requirements a certain way.

That’s not a fair statement. To be clear, nobody is asking to have anyone *forced* to do anything here except you. We want parentheses to be *optional* (use them if you find them an aid to clarity and readability). You’re arguing that the language *forces* all of us to use parentheses for *every* existential type *everywhere*.

I have no objection to you *preferring* the style of always using the outer parentheses. The community might even come to the conclusion that this is the best practice. But I don’t see a good reason to *require* them in the formal syntax of the language.

···

On May 27, 2016, at 1:36 PM, Austin Zheng <austinzheng@gmail.com> wrote:
On Fri, May 27, 2016 at 10:09 AM, Thorsten Seitz <tseitz42@icloud.com <mailto:tseitz42@icloud.com>> wrote:

Am 27.05.2016 um 18:36 schrieb Austin Zheng <austinzheng@gmail.com <mailto:austinzheng@gmail.com>>:

-Thorsten

I hope that explains my reasoning.

Best,
Austin

On May 27, 2016, at 9:28 AM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

Sent from my iPad

On May 27, 2016, at 11:18 AM, Austin Zheng <austinzheng@gmail.com <mailto:austinzheng@gmail.com>> wrote:

Here's a strawman idea.

What if we go with '&' and 'where', but we enclose the whole thing in parentheses?

(class & Protocol1 & Protocol2 where .Foo == Int, .Bar : Baz)

There are a couple of reasons I propose this syntax:

- It makes it very clear where the definition of the type begins and ends. I understand people really despise angle brackets, but I really want some way to visually delineate the boundaries of the type. Plus, I imagine it makes syntax a little easier to parse and preemptively forbids some ambiguities.

- It's a structural, not nominal, type, like a tuple, so it uses parens as well. This reserves "<" and ">" for generic types.

- The '&' is easily understood - "Protocol1" *and* "Protocol2". It's also a signal that order doesn't matter - just like how order matters with things that use commas, like argument lists, tuples, and array members, order doesn't generally matter with bitwise or logical 'and' operators.

- If we ever decide to have union types, we have a very elegant third form of nominal type syntax that naturally falls out: (MyClass1 | MyClass2 | MyClass3).

Thoughts?

Generally in favor. But I would not require the parentheses. I believe they would be allowed optionally automatically, just as (Int) is the same as Int (because single element tuples don't exist and the underlying type is used directly instead). It seems better to leave parentheses up to a matter of style.

Austin

On May 27, 2016, at 9:07 AM, Thorsten Seitz via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Am 27.05.2016 um 16:54 schrieb Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>>:

On May 27, 2016, at 8:18 AM, Thorsten Seitz via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Personally I think `&` is more lightweight (and it is established in other languages like Ceylon and Typescript) and `where` is more expressive (and established in Swift for introducing constraints), so I would stay with these.

I agree. If we can make `&` with `where` work syntactically it would be nice to go in this lighter weight direction. If we decide to do that the question then becomes what to do with `protocol`. Would it be feasible to replace it with `&` in Swift 3 if we decide on that direction?

Yep. `protocol` should be replaced with `&` in that case.

-Thorsten

-Thorsten

Am 27.05.2016 um 14:34 schrieb Vladimir.S <svabox@gmail.com <mailto:svabox@gmail.com>>:

Btw, in case we have `where` keyword in syntax related to types/protocols (when defining constrains. and not some symbol like '>>'.. don't know, for example), why we can't have 'and' keyword also when discuss the syntax of type/protocol conjunction?
I.e.

let x: P and Q
let x: P and Q where P.T == Q.T
let x: P and Q and R

or, for consistency, as I understand it, we should have
let x: P & Q >> P.T == Q.T

On 27.05.2016 11:55, Thorsten Seitz via swift-evolution wrote:

We could just write

let x: P & Q
instead of
let x: Any<P, Q>

let x: Collection where .Element: P
instead of
let x: Any<Collection where .Element: P>

let x: P & Q where P.T == Q.T
instead of
let x: Any<P, Q where P.T == Q.T>

let x: P & Q & R
instead of
let x: Any<P, Q, R>

let x: Collection
instead of
let x: Any<Collection>

This would avoid the confusion of Any<T1, T2> being something completely
different than a generic type (i.e. order of T1, T2 does not matter whereas
for generic types it is essential).

-Thorsten

Am 26.05.2016 um 20:11 schrieb Adrian Zubarev via swift-evolution
<swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>>:

Something like |type<…>| was considered at the very start of the whole
discussion (in this thread
<https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160502/016523.html&gt;\),
but it does not solve the meaning of an existential type and also might
lead to even more confusion.

From my perspective I wouldn’t use parentheses here because it looks more
like an init without any label |Type.init(…)| or |Type(…)|. I could live
with |Any[…]| but this doesn’t look shiny and Swifty to me. Thats only my
personal view. ;)

--
Adrian Zubarev
Sent with Airmail

Am 26. Mai 2016 bei 19:48:04, Vladimir.S via swift-evolution
(swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>) schrieb:

Don't think {} is better here, as they also have "established meaning in
Swift today".

How about just Type(P1 & P2 | P3) - as IMO we can think of such
construction as "creation" of new type and `P1 & P2 | P3` could be treated
as parameters to initializer.

func f(t: Type(P1 & P2 | P3)) {..}

On 26.05.2016 20:32, L. Mihalkovic via swift-evolution wrote:
> How about something like Type{P1 & P2 | P3} the point being that "<...>" has an established meaning in Swift today which is not what is expressed in the "<P1,P2,P3>" contained inside Any<P1, P2,P3>.
>
>> On May 26, 2016, at 7:11 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>> wrote:
>>
>>
>>> on Thu May 26 2016, Adrian Zubarev <swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>> wrote:
>>>
>>> There is great feedback going on here. I'd like to consider a few things here:
>>>
>>> * What if we name the whole thing `Existential<>` to sort out all
>>> confusion?
>>
>> Some of us believe that “existential” is way too theoretical a word to
>> force into the official lexicon of Swift. I think “Any<...>” is much
>> more conceptually accessible.
>>
>>>
>>> This would allow `typealias Any = Existential<>`. * Should
>>> `protocol A: Any<class>` replace `protocol A: class`? Or at least
>>> deprecate it. * Do we need `typealias AnyClass = Any<class>` or do we
>>> want to use any class requirement existential directly? If second, we
>>> will need to allow direct existential usage on protocols (right now we
>>> only can use typealiases as a worksround).
>>
>> --
>> Dave
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto: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> <mailto: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> <mailto: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> <mailto: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 <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

From the point of view of the type system `P & Q` is an anonymous supertype of `P` and `Q`.
This would be just the same if the syntax was `Any<P, Q>`. I don’t see a semantic difference here.

Whether that is a "container“ or not seems to be an implementation detail to me but should have nothing to do with the type system.
In what way should it be "lossy“?

what is by definition lossy, is the relationship between a type and an existential type that can represent it. Comes from the fact that there is no way to go back to the type we started from once all we hold is the existential (i.e. means it is a one —> n mapping relationship, not a 1 —> 1). Not the notation.
right?

Right. A protocol with associated types is more like a type family than a type.

protocol P {
  associatedtype T

  var a: T
  func f(_ value: T) -> Int
}

any<P> represents the whole type family with unbound T, i.e. a set of types with one element for each possible value of T
any<P where T: Equatable> represents a subset of the whole type family, i.e. all elements where T conforms to Equatable
any<P where T == Int> represents a concrete type, i.e. one element of the whole type family

So, like you say, the semantics are clear and are independent of the notation.

Am I missing something?

I was a bit confused as well and had to read this several times. I think this is talking about a syntactic “container” - i.e. brackets of some kind (as opposed to a “free floating” syntax). I don’t think it is talking about a semantic difference of any kind. But maybe I am still confused an not understanding what was intended...

given the semantic we wish to express (combination of conformance declarations), what possible ways do we have to express it. It come down to 2 families of syntax: the ‘container’ form, of which I gave a few examples, versus the non-container form (or free-floating conformance list) of which the straight list is the most obvious, but not the only one.

Ok, so you meant the syntactical form of `any<…>` with "container“. Agreed.

Joe Groff was reminding us that the second group of syntax also exists.

Compilers love Any<P...Q> , people’s brains love P & Q

Yes, at least mine :-)

-Thorsten

···

Am 27.05.2016 um 17:15 schrieb L Mihalkovic <laurent.mihalkovic@gmail.com>:

On May 27, 2016, at 4:52 PM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

On May 27, 2016, at 7:20 AM, Thorsten Seitz via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

-Thorsten

Am 27.05.2016 um 12:30 schrieb L. Mihalkovic <laurent.mihalkovic@gmail.com <mailto:laurent.mihalkovic@gmail.com>>:

It seem to me we are debating the how of a what that has not been defined. The root question behind all these alternatives seems to be to decide if the existential-ness should be carried by a 'container' that is then refined internally, or derived from the presence of the free-floating refinements. This is the question that splits the possible syntaxes into these 2 groups:

Any<> Any
Type<> Type<>

this was meant to read
Type<…> Type { …. } Type[ … ]

Existential<>

and the (these are all straw man representations that should not limit the thinking)

P & Q
@P and @Q
is P , Q
P & Q typed

If the answer is to use a 'container' then the next question is to see its relationship to the other existing containers: is it the result of a transformation, is it a superset, or a super type; it is obviously lossy, but not entirely if the solution follows in some of Brent's past suggestion to make some existential types instantiate-able (which opens a very similar problem to what java faced for several years when trying to identify a universal collection literal syntax).
That will narrow down the field of possible matches... until one syntax emerges as conveying the meaning that is reflected by the answers to each question.

On May 27, 2016, at 10:55 AM, Thorsten Seitz via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

We could just write

let x: P & Q
instead of
let x: Any<P, Q>

let x: Collection where .Element: P
instead of
let x: Any<Collection where .Element: P>

let x: P & Q where P.T == Q.T
instead of
let x: Any<P, Q where P.T == Q.T>

let x: P & Q & R
instead of
let x: Any<P, Q, R>

let x: Collection
instead of
let x: Any<Collection>

This would avoid the confusion of Any<T1, T2> being something completely different than a generic type (i.e. order of T1, T2 does not matter whereas for generic types it is essential).

-Thorsten

Am 26.05.2016 um 20:11 schrieb Adrian Zubarev via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

Something like type<…> was considered at the very start of the whole discussion (in this thread <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160502/016523.html&gt;\), but it does not solve the meaning of an existential type and also might lead to even more confusion.

From my perspective I wouldn’t use parentheses here because it looks more like an init without any label Type.init(…) or Type(…). I could live with Any[…] but this doesn’t look shiny and Swifty to me. Thats only my personal view. ;)

--
Adrian Zubarev
Sent with Airmail

Am 26. Mai 2016 bei 19:48:04, Vladimir.S via swift-evolution (swift-evolution@swift.org <mailto:swift-evolution@swift.org>) schrieb:

Don't think {} is better here, as they also have "established meaning in
Swift today".

How about just Type(P1 & P2 | P3) - as IMO we can think of such
construction as "creation" of new type and `P1 & P2 | P3` could be treated
as parameters to initializer.

func f(t: Type(P1 & P2 | P3)) {..}

On 26.05.2016 20:32, L. Mihalkovic via swift-evolution wrote:
> How about something like Type{P1 & P2 | P3} the point being that "<...>" has an established meaning in Swift today which is not what is expressed in the "<P1,P2,P3>" contained inside Any<P1, P2,P3>.
>
>> On May 26, 2016, at 7:11 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>
>>
>>> on Thu May 26 2016, Adrian Zubarev <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>
>>> There is great feedback going on here. I'd like to consider a few things here:
>>>
>>> * What if we name the whole thing `Existential<>` to sort out all
>>> confusion?
>>
>> Some of us believe that “existential” is way too theoretical a word to
>> force into the official lexicon of Swift. I think “Any<...>” is much
>> more conceptually accessible.
>>
>>>
>>> This would allow `typealias Any = Existential<>`. * Should
>>> `protocol A: Any<class>` replace `protocol A: class`? Or at least
>>> deprecate it. * Do we need `typealias AnyClass = Any<class>` or do we
>>> want to use any class requirement existential directly? If second, we
>>> will need to allow direct existential usage on protocols (right now we
>>> only can use typealiases as a worksround).
>>
>> --
>> Dave
>>
>> _______________________________________________
>> 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 <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 <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

Austin raised the point (or reminded of Joe’s raising the point) of possible problems when returning constrained existentials from generic functions:

func foo<P, Q>(p: P, q: Q) -> any<Collection where .Element == P> where P: Equatable { … }

would require parentheses when using `&` instead of any<>

func foo<P, Q>(p: P, q: Q) -> (Collection where .Element == P) where P: Equatable { … }

This would even be the case if there was no constraint on P:

func foo<P, Q>(p: P, q: Q) -> (Collection where .Element == P) { … }

An alternative would be to use `with` for existentials instead of `where`:

func foo<P, Q>(p: P, q: Q) -> Collection with .Element == P where P: Equatable { … }

But even then this would be more readable either with parentheses (now just as a matter of style) or a line break:

func foo<P, Q>(p: P, q: Q) -> Collection with .Element == P
  where P: Equatable { … }

-Thorsten

We could make parentheses optional in the general case, and just have them mandatory in the following situations:

- You want to nest an existential literal inside another existential literal:
let a : Protocol1, (Protocol2 where .Blah == Int), Protocol3 = foo()

- You want to return an existential with more than one term and/or a where clause from a function that has a generic where clause
func foo<P, Q>(p: P, q: Q) -> (Collection with .Element == P) where P : Equatable { ... }

- You want to use an existential as a function argument, and that existential has more than one term and/or a where clause
func foo(x: Protocol1, y: (Protocol2 where .Blah == Int), z: Protocol3) { ... }

Would that be a reasonable compromise?

···

On May 28, 2016, at 10:26 AM, Thorsten Seitz <tseitz42@icloud.com> wrote:

-Matthew

typealias P3Int = Protocol 3 where .Foo == Int
let x : Protocol1, Protocol2, P3Int where Protocol2.Bar : Baz

If you are writing the entire type in a single location I expect the conventional style to be like this:

let x : Protocol1, Protocol2, Protocol 3 where Protocol2.Bar : Baz, Protocol3.Foo == Int

With all associated types constraints in a single `where` clause as we other places they are written in Swift.

Maybe I am wrong about that and a different conventional style would emerge (for example, where clauses clustered with the related protocol).

But *requiring* parentheses is really orthogonal to the style issue of where and when it is considered *advisable* to use them.

-Matthew

I hope that explains my reasoning.

Best,
Austin

On May 27, 2016, at 9:28 AM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

Sent from my iPad

On May 27, 2016, at 11:18 AM, Austin Zheng <austinzheng@gmail.com <mailto:austinzheng@gmail.com>> wrote:

Here's a strawman idea.

What if we go with '&' and 'where', but we enclose the whole thing in parentheses?

(class & Protocol1 & Protocol2 where .Foo == Int, .Bar : Baz)

There are a couple of reasons I propose this syntax:

- It makes it very clear where the definition of the type begins and ends. I understand people really despise angle brackets, but I really want some way to visually delineate the boundaries of the type. Plus, I imagine it makes syntax a little easier to parse and preemptively forbids some ambiguities.

- It's a structural, not nominal, type, like a tuple, so it uses parens as well. This reserves "<" and ">" for generic types.

- The '&' is easily understood - "Protocol1" *and* "Protocol2". It's also a signal that order doesn't matter - just like how order matters with things that use commas, like argument lists, tuples, and array members, order doesn't generally matter with bitwise or logical 'and' operators.

- If we ever decide to have union types, we have a very elegant third form of nominal type syntax that naturally falls out: (MyClass1 | MyClass2 | MyClass3).

Thoughts?

Generally in favor. But I would not require the parentheses. I believe they would be allowed optionally automatically, just as (Int) is the same as Int (because single element tuples don't exist and the underlying type is used directly instead). It seems better to leave parentheses up to a matter of style.

Austin

On May 27, 2016, at 9:07 AM, Thorsten Seitz via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Am 27.05.2016 um 16:54 schrieb Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>>:

On May 27, 2016, at 8:18 AM, Thorsten Seitz via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Personally I think `&` is more lightweight (and it is established in other languages like Ceylon and Typescript) and `where` is more expressive (and established in Swift for introducing constraints), so I would stay with these.

I agree. If we can make `&` with `where` work syntactically it would be nice to go in this lighter weight direction. If we decide to do that the question then becomes what to do with `protocol`. Would it be feasible to replace it with `&` in Swift 3 if we decide on that direction?

Yep. `protocol` should be replaced with `&` in that case.

-Thorsten

-Thorsten

Am 27.05.2016 um 14:34 schrieb Vladimir.S <svabox@gmail.com <mailto:svabox@gmail.com>>:

Btw, in case we have `where` keyword in syntax related to types/protocols (when defining constrains. and not some symbol like '>>'.. don't know, for example), why we can't have 'and' keyword also when discuss the syntax of type/protocol conjunction?
I.e.

let x: P and Q
let x: P and Q where P.T == Q.T
let x: P and Q and R

or, for consistency, as I understand it, we should have
let x: P & Q >> P.T == Q.T

On 27.05.2016 11:55, Thorsten Seitz via swift-evolution wrote:

We could just write

let x: P & Q
instead of
let x: Any<P, Q>

let x: Collection where .Element: P
instead of
let x: Any<Collection where .Element: P>

let x: P & Q where P.T == Q.T
instead of
let x: Any<P, Q where P.T == Q.T>

let x: P & Q & R
instead of
let x: Any<P, Q, R>

let x: Collection
instead of
let x: Any<Collection>

This would avoid the confusion of Any<T1, T2> being something completely
different than a generic type (i.e. order of T1, T2 does not matter whereas
for generic types it is essential).

-Thorsten

Am 26.05.2016 um 20:11 schrieb Adrian Zubarev via swift-evolution
<swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>>:

Something like |type<…>| was considered at the very start of the whole
discussion (in this thread
<https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160502/016523.html&gt;\),
but it does not solve the meaning of an existential type and also might
lead to even more confusion.

From my perspective I wouldn’t use parentheses here because it looks more
like an init without any label |Type.init(…)| or |Type(…)|. I could live
with |Any[…]| but this doesn’t look shiny and Swifty to me. Thats only my
personal view. ;)

--
Adrian Zubarev
Sent with Airmail

Am 26. Mai 2016 bei 19:48:04, Vladimir.S via swift-evolution
(swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>) schrieb:

Don't think {} is better here, as they also have "established meaning in
Swift today".

How about just Type(P1 & P2 | P3) - as IMO we can think of such
construction as "creation" of new type and `P1 & P2 | P3` could be treated
as parameters to initializer.

func f(t: Type(P1 & P2 | P3)) {..}

On 26.05.2016 20:32, L. Mihalkovic via swift-evolution wrote:
> How about something like Type{P1 & P2 | P3} the point being that "<...>" has an established meaning in Swift today which is not what is expressed in the "<P1,P2,P3>" contained inside Any<P1, P2,P3>.
>
>> On May 26, 2016, at 7:11 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>> wrote:
>>
>>
>>> on Thu May 26 2016, Adrian Zubarev <swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>> wrote:
>>>
>>> There is great feedback going on here. I'd like to consider a few things here:
>>>
>>> * What if we name the whole thing `Existential<>` to sort out all
>>> confusion?
>>
>> Some of us believe that “existential” is way too theoretical a word to
>> force into the official lexicon of Swift. I think “Any<...>” is much
>> more conceptually accessible.
>>
>>>
>>> This would allow `typealias Any = Existential<>`. * Should
>>> `protocol A: Any<class>` replace `protocol A: class`? Or at least
>>> deprecate it. * Do we need `typealias AnyClass = Any<class>` or do we
>>> want to use any class requirement existential directly? If second, we
>>> will need to allow direct existential usage on protocols (right now we
>>> only can use typealiases as a worksround).
>>
>> --
>> Dave
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org <mailto:swift-evolution@swift.org> <mailto: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> <mailto: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> <mailto: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> <mailto: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 <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

Sorry, 'with' in the second example should be 'where'. My personal preference is to keep 'where' for both uses, since they are serving the same purpose.

···

On May 28, 2016, at 10:33 AM, Austin Zheng <austinzheng@gmail.com> wrote:

-Thorsten

We could make parentheses optional in the general case, and just have them mandatory in the following situations:

- You want to nest an existential literal inside another existential literal:
let a : Protocol1, (Protocol2 where .Blah == Int), Protocol3 = foo()

- You want to return an existential with more than one term and/or a where clause from a function that has a generic where clause
func foo<P, Q>(p: P, q: Q) -> (Collection with .Element == P) where P : Equatable { ... }

- You want to use an existential as a function argument, and that existential has more than one term and/or a where clause
func foo(x: Protocol1, y: (Protocol2 where .Blah == Int), z: Protocol3) { ... }

Would that be a reasonable compromise?

Sorry, 'with' in the second example should be 'where'. My personal preference is to keep 'where' for both uses, since they are serving the same purpose.

-Thorsten

We could make parentheses optional in the general case, and just have them mandatory in the following situations:

- You want to nest an existential literal inside another existential literal:
let a : Protocol1, (Protocol2 where .Blah == Int), Protocol3 = foo()

When using `&` instead of `,` this would not be required (not even for readability IMO).

- You want to return an existential with more than one term and/or a where clause from a function that has a generic where clause
func foo<P, Q>(p: P, q: Q) -> (Collection with .Element == P) where P : Equatable { … }

For return types (if staying with `where` instead of `with`) the parentheses would be required iff only one `where` is present.
They would not be strictly required if two `where` clauses would be present, but I would be ok if they would be mandatory in that case.

- You want to use an existential as a function argument, and that existential has more than one term and/or a where clause
func foo(x: Protocol1, y: (Protocol2 where .Blah == Int), z: Protocol3) { … }

I wouldn’t require them here. For one the function does not look too bad without the parentheses:

func foo(x: Protocol1, y: Protocol2 where .Blah == Int, z: Protocol3) { … }

But even more important: when formatting this function across multiple lines (which I might rather do to improve readability instead of adding parentheses) I would definitely *not* want to have to use parentheses:

func foo(
  x: Protocol1,
  y: Protocol2 where .Blah == Int,
  z: Protocol3)
{ … }

-Thorsten

···

Am 28.05.2016 um 19:35 schrieb Austin Zheng <austinzheng@gmail.com>:

On May 28, 2016, at 10:33 AM, Austin Zheng <austinzheng@gmail.com <mailto:austinzheng@gmail.com>> wrote:

Sorry, 'with' in the second example should be 'where'. My personal preference is to keep 'where' for both uses, since they are serving the same purpose.

-Thorsten

We could make parentheses optional in the general case, and just have them mandatory in the following situations:

- You want to nest an existential literal inside another existential literal:
let a : Protocol1, (Protocol2 where .Blah == Int), Protocol3 = foo()

When using `&` instead of `,` this would not be required (not even for readability IMO).

- You want to return an existential with more than one term and/or a where clause from a function that has a generic where clause
func foo<P, Q>(p: P, q: Q) -> (Collection with .Element == P) where P : Equatable { … }

For return types (if staying with `where` instead of `with`) the parentheses would be required iff only one `where` is present.
They would not be strictly required if two `where` clauses would be present, but I would be ok if they would be mandatory in that case.

- You want to use an existential as a function argument, and that existential has more than one term and/or a where clause
func foo(x: Protocol1, y: (Protocol2 where .Blah == Int), z: Protocol3) { … }

I wouldn’t require them here. For one the function does not look too bad without the parentheses:

func foo(x: Protocol1, y: Protocol2 where .Blah == Int, z: Protocol3) { … }

But even more important: when formatting this function across multiple lines (which I might rather do to improve readability instead of adding parentheses) I would definitely *not* want to have to use parentheses:

func foo(
  x: Protocol1,
  y: Protocol2 where .Blah == Int,
  z: Protocol3)
{ … }

I agree with everything Thorsten said. Parents are used to resolve ambiguity. If we need to go a bit further than is strictly necessary for that purpose in order to make return types feel a bit more consistent that is ok. I don't mind requiring them for a return type with a where clause, but that's as far as I'd go.

···

Sent from my iPad

On May 28, 2016, at 12:50 PM, Thorsten Seitz <tseitz42@icloud.com> wrote:

Am 28.05.2016 um 19:35 schrieb Austin Zheng <austinzheng@gmail.com>:

On May 28, 2016, at 10:33 AM, Austin Zheng <austinzheng@gmail.com> wrote:

-Thorsten