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

-10 using a comma knowing that it creates ambiguity and then forcing to use brackets to disambiguate make no logical sense when there are plenty of other choices that make the grammar so much easier to read/implement

Regards
(From mobile)

···

On May 24, 2016, at 9:25 PM, Tyler Cloutier via swift-evolution <swift-evolution@swift.org> wrote:

On May 24, 2016, at 12:07 PM, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

'Any' is definitely a better name, but I think this is still syntax only a compiler can love. If we're going to repaint this bikeshed, I think we should also consider as an alternative some form of infix syntax for composing constraints. Rust uses `P1 + P2`, and various C++ proposals have suggested `P1 && P2`. Some pros(+) and cons(-) I can see with this approach:

+ Infix notation works not only in type position, but constraint position as well, providing a nicer way to express multiple type variable constraints:
  var x: P && Q
  func foo<T: P && Q, U>(x: T)

+ Infix notation feels subjectively lighter, being less nesty and angle-bracket-blinding. Compare the above with:
  var x: Any<P, Q>
  func foo<T: Any<P,Q>, U>(x: T)

Perhaps just a comma separated list like a type-inheritance-clause, using parenthesis for disambiguation?

var x: P, Q
func foo<(T: P, Q), U>

or

func foo<T: (P, Q), U>

Particularly in the second declaration, I find the nested angle brackets and comma delimiters to be hard to visually parse.

± Like 'Any', an infix operator doesn't pass judgment on what kinds of constraint is being applied, so it naturally extends to expressing class-with-protocol constraints.

- Infix notation doesn't provide an obvious place for generalized existentials to hang secondary constraints. The angle brackets for Any provide an enclosed syntactic space we can easily stuff a 'where' clause:

  func sum(_ collection: Any<Sequence where Element == Int>) -> Int { ... }

(though this notation still feels heavy and awkward to me).

- The bracketing of `Any` might let us address the curious case of protocol vs existential metatypes in a better way. Right now, the static metatype for a protocol type (the type of `P.self`) is spelled `P.Protocol`, and the dynamic metatype for any type conforming to the protocol (the erased type of `T.self` where T: P) is spelled `P.Type`. Unintuitively, when a protocol type is substituted into `T.Type` in a generic context, you get the static type `P.Protocol` rather than `P.Type`, for soundness reasons:

  func staticType<T>(of _: T) -> T.Type { return T.self }

This substitution behavior could be made clearer if we moved a dynamic metatype's `.Type` into the Any brackets, so that `Any<P.Type>` would be the dynamic metatype of any type conforming to P, and `Any<P>.Type` would be the static metatype of the type `Any<P>`. Infix notation doesn't provide an opportunity to make this clarification.

- A few people have also noted the similarity between Any<...> and normal generic types. This is potentially confusing today, but with enough magic language features from the future, Any *could* conceivably be made a library feature in the fullness of time:

  // Let's say 'protocol' constraints indicate second-order constraint variables:
  enum Any<Constraints: protocol> {
    // And we have GADTs:
    case value<T: Constraints>(T)
  }

  // And we have user-defined value subtyping:
  extension <Constraints: protocol, T: Constraints> T: Any<Constraints> { ... }

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

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

I am not going to comment on the proposal (conflict of interest etc). I do want to speak up in support of Brent's points, though.

  * What is your evaluation of the proposal?

I am in favor. This is a necessary step towards many future features: class-plus-protocol types, the replacement/reimplementation of AnyObject with Any<class>, existentials with associated types, etc.

One reason to prefer `Any` over `any` which is not listed in the proposal is confusion with the unparameterized `Any` type. Having an uppercase `Any` and a lowercase `any<…>` is going to lead to a lot of confusion; people aren't going to remember whether they need the capitalized form or the lowercase one for any particular use. I don't think we can have `any<...>` unless we're also willing to have an unparameterized `any`, and I think `any` is 100% wrong, because it is absolutely a type but is lowercase.

Since we are trying to cram as many breaking changes as possible into Swift 3, I also think we should consider now, or soon, whether or not we want to draw a strong syntactic line between protocols-as-existentials and protocols-as-constraints by requiring the use of `Any<…>` on all existentials and forbidding its use in constraints. That would mean, for instance, that code like this:

  let printable: CustomStringConvertible = foo

Would now be written:

  let printable: Any<CustomStringConvertible> = foo

I'm sure this will be controversial, but I like the idea of marking all existential types using Any-syntax. It makes the distinction between concrete and existential types in code completely clear to the reader. Given that there are some subtle differences in how concrete and existential types can be used (for example, used as the types of values passed to generic functions), I think this is definitely worth considering.

There are an additional five characters (including two angle brackets to type), but I suspect bare existentials aren't used quite as often as concrete types are, so the aesthetic cost might not be too onerous.

And also that code like:

  func foo<X: Any<Y, Z>>(x: X)

Would probably have to be written something like:

  func foo<X: Y>(x: X) where X: Z

I also personally prefer this convention. The 'Any<Y, Z>' construct in the constraint above does not really have anything to do with existential types as they exist everywhere else in Swift; it simply means that whatever concrete type can be used to instantiate the function must conform to two different protocols.

I don’t mind banning the direct use of `Any` in constraints and agree that would be bad style. But if we are going to remove the ability to use typealiases bound to `Any` in constraints we need to introduce an alternative mechanism for factoring out constraints (hopefully a superior mechanism that can abstract over constraints that relate generic parameters to each other).

···

On May 25, 2016, at 3:01 AM, Austin Zheng via swift-evolution <swift-evolution@swift.org> wrote:

On May 25, 2016, at 12:34 AM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

It's true that any concrete type that could be used to satisfy X in foo() could also be used to fill an Any<Y, Z> existential, but this correspondence isn't interesting to the user. The ways a user can use an Any<Y, Z> existential differ from the ways a sort-of-universal type like X in foo() can be used:

// firstElement's type is known exactly at compile time, because X must be 'filled in'
// by a concrete type, and that concrete type's associated types are also known.
foo<X : Collection>(x: X) {
let firstElement : X.Iterator.Element = x.first!
}

// firstElement's type is not ever known without some sort of dynamic downcasting,
// because the contract that defines the existential can guarantee nothing about its type.
let foo : <X : Collection> = ...
let firstElement : Any = x.first!

However, I believe this would have a significant advantage: it would clarify the distinction between an existential and a constraint. It would more clearly mark where you are taking on the abstraction overhead of an existential. It would also improve the non-existential type situation: in the short term, it would make it clearer where uses of associated type protocols like `Comparable` would not be permitted; in the long term, once we have type-erased existentials for those protocols, it would make it clearer when type erasure was in effect.

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

Yes. `protocol<>` is an ugly and unloved corner of the language; very few people know about it, remember it, or use it. The renaming improves this situation.

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

Given the way it enables many future features, yes.

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

The only language I've used with similar features is Objective-C. There, too, the `<>` is overloaded, now that lightweight generics are part of the language.

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

I'd like to think I have a fairly deep understanding of this feature, having participated heavily in the discussions about it.

--
Brent Royal-Gordon
Architechies

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

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

I am not going to comment on the proposal (conflict of interest etc). I do want to speak up in support of Brent's points, though.

   * What is your evaluation of the proposal?

I am in favor. This is a necessary step towards many future features: class-plus-protocol types, the replacement/reimplementation of AnyObject with Any<class>, existentials with associated types, etc.

One reason to prefer `Any` over `any` which is not listed in the proposal is confusion with the unparameterized `Any` type. Having an uppercase `Any` and a lowercase `any<…>` is going to lead to a lot of confusion; people aren't going to remember whether they need the capitalized form or the lowercase one for any particular use. I don't think we can have `any<...>` unless we're also willing to have an unparameterized `any`, and I think `any` is 100% wrong, because it is absolutely a type but is lowercase.

Since we are trying to cram as many breaking changes as possible into Swift 3, I also think we should consider now, or soon, whether or not we want to draw a strong syntactic line between protocols-as-existentials and protocols-as-constraints by requiring the use of `Any<…>` on all existentials and forbidding its use in constraints. That would mean, for instance, that code like this:

   let printable: CustomStringConvertible = foo

Would now be written:

   let printable: Any<CustomStringConvertible> = foo

I'm sure this will be controversial, but I like the idea of marking all existential types using Any-syntax. It makes the distinction between concrete and existential types in code completely clear to the reader. Given that there are some subtle differences in how concrete and existential types can be used (for example, used as the types of values passed to generic functions), I think this is definitely worth considering.

Much of what I read about the swift philosophy seems to boil down to immediate association of the semantic with the syntax, to help the newcomer 'parse' the language in their mind with less efforts. Seems to me that Any<> being so close to Array<> could be construed as running counter to that philosophie.

···

On May 25, 2016, at 10:01 AM, Austin Zheng via swift-evolution <swift-evolution@swift.org> wrote:

On May 25, 2016, at 12:34 AM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

There are an additional five characters (including two angle brackets to type), but I suspect bare existentials aren't used quite as often as concrete types are, so the aesthetic cost might not be too onerous.

And also that code like:

   func foo<X: Any<Y, Z>>(x: X)

Would probably have to be written something like:

   func foo<X: Y>(x: X) where X: Z

I also personally prefer this convention. The 'Any<Y, Z>' construct in the constraint above does not really have anything to do with existential types as they exist everywhere else in Swift; it simply means that whatever concrete type can be used to instantiate the function must conform to two different protocols.

It's true that any concrete type that could be used to satisfy X in foo() could also be used to fill an Any<Y, Z> existential, but this correspondence isn't interesting to the user. The ways a user can use an Any<Y, Z> existential differ from the ways a sort-of-universal type like X in foo() can be used:

// firstElement's type is known exactly at compile time, because X must be 'filled in'
// by a concrete type, and that concrete type's associated types are also known.
foo<X : Collection>(x: X) {
let firstElement : X.Iterator.Element = x.first!
}

// firstElement's type is not ever known without some sort of dynamic downcasting,
// because the contract that defines the existential can guarantee nothing about its type.
let foo : <X : Collection> = ...
let firstElement : Any = x.first!

However, I believe this would have a significant advantage: it would clarify the distinction between an existential and a constraint. It would more clearly mark where you are taking on the abstraction overhead of an existential. It would also improve the non-existential type situation: in the short term, it would make it clearer where uses of associated type protocols like `Comparable` would not be permitted; in the long term, once we have type-erased existentials for those protocols, it would make it clearer when type erasure was in effect.

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

Yes. `protocol<>` is an ugly and unloved corner of the language; very few people know about it, remember it, or use it. The renaming improves this situation.

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

Given the way it enables many future features, yes.

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

The only language I've used with similar features is Objective-C. There, too, the `<>` is overloaded, now that lightweight generics are part of the language.

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

I'd like to think I have a fairly deep understanding of this feature, having participated heavily in the discussions about it.

--
Brent Royal-Gordon
Architechies

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

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

- A few people have also noted the similarity between Any<...> and normal generic types. This is potentially confusing today, but with enough magic language features from the future, Any *could* conceivably be made a library feature in the fullness of time:

   // Let's say 'protocol' constraints indicate second-order constraint variables:
   enum Any<Constraints: protocol> {
       // And we have GADTs:
       case value<T: Constraints>(T)
   }

   // And we have user-defined value subtyping:
   extension <Constraints: protocol, T: Constraints> T: Any<Constraints> { ... }

I wanted to reply to this, because this is a beautiful dream, but if we want to treat `Any` like some kind of magical variadic generic type, that has some interesting implications for its design right now.

1) In a normal generic type, when you leave out the generic parameters, Swift infers them. (Think of casting an array literal to `Array`, which pins down the collection type but not the elements.) If `Any` were handled similarly, that would mean that `foo as Any` would not necessarily have an empty set of constraints, but would rather have an *inferred* set of constraints. If you wanted to force it to have no constraints, you would need to write `Any<>`.

2) We would not normally expect to be able to cast between a normal generic type and the instance contained in it. Instead, we would expect to use initializers, just as we're now planning to require for Objective-C bridging:

   let myExistentialInteger = Any<Integer>(myInt)
   let myInt2 = Int(any: myExistentialInteger)!

How realistic is it to plan something like that considering the details involved in something like (even just to filter it out):

  let myEx = Any<Iterable>([10,"london",20,"tokyo"])

and then would you then propose something like:

let myExistentialInteger = Any<Integer>(myInt) {
  func hashValue -> Int {
    return 42
  }
}

···

On May 25, 2016, at 9:45 AM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

Note that, if we were passing to an API which specifically expected an `Any<Integer>`, we could just write `Any(myInt)` and type inference would figure out the rest.

--
Brent Royal-Gordon
Architechies

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

After thinking about this topic for the past few days, I'd like to throw in
my support for "Any<>" as well. It's one magic construct to learn, looks
like a type, has the visual delineation, and shares continuity with both
protocol<> and Any today.

I'd also like to express my support for the proposal to delineate generic
and existential syntax: all existentials must be written with Any<...>;
generic type constraints cannot use it. I hope this will make it clear to
people learning and using the language that, despite their superficial
similarities, they are actually two different concepts.

Austin

···

On Wed, Jun 1, 2016 at 1:59 PM, Brent Royal-Gordon via swift-evolution < swift-evolution@swift.org> wrote:

> [Proposal:
https://github.com/apple/swift-evolution/blob/master/proposals/0095-any-as-existential.md
]
>
> I’m late again to this one, but the discussion’s certainly still going.
I’m pretty strongly against the bare ‘A & B’ syntax, for a few reasons:
>
> - Swift doesn’t use ‘&’ for anything except bitwise AND. In particular,
it didn’t get picked for set intersection.

I very, *very* much agree with this point. Thus far, Swift has been very
conservative about overloading. It seems bizarre that we would violate that
policy for these type combinators when much closer matches have been passed
over.

I also think that using `&` absolutely *begs* to have an `|` as well, and
as much as the Ceylon people clamor for them, I don't think union types
make sense in Swift. Unlike Ceylon, Swift uses an algebraic data type for
Optional, doesn't use type-erased generics, and supports overloading. As
far as I can tell, *none* of the reasons cited in the Ceylon language
design FAQ <Eclipse Ceylon™ | projects.eclipse.org;
apply to Swift.

(P.S. That language design FAQ is a *fantastic* document.)

> - In theory people are allowed to overload ‘&’ to operate on types. That
doesn’t make sense for all types, but you could probably come up with a
particular type hierarchy or use of generics where it does make sense.
>
> - I don’t like types with spaces in them when the spaces aren’t
bracketed in some way. This is entirely an aesthetic objection, of the form
“I don’t naturally read that as a type, or even as a single unit, when
looking at code.” This isn’t a great objection because someone could have
said it about `[Int]` or `Int?` as well. (It would be a more realistic
objection if some of our brackets weren’t “<" and “>”.)

To augment this: I think that if we're going to see a lot of little
`where` clauses attached to types, you kind of have to have a bracketing
syntax to put them in. And no, `(Collection where .Element == String)`
doesn't count. `()` is about precedence, and this isn't a question of
precedence; it's a question of making the type read as a single unit.

> And I still support the ‘Any’ syntax, despite the “order doesn’t matter”
problem:
>
> - It’s consistent with the existing unconstrained ‘Any’ and with the
current dedicated wrapper types. If we didn’t think it was a good name for
those, we wouldn’t use it there either.

One of my concerns with the `&` syntax is that it leaves no good way to
define `Any`. I don't like having a magic `&` operator *and* a magic `Any`
keyword, neither of which derives from anything more general.

> - It’s easily learnable. It’s rare enough that someone wouldn’t be
exposed to it right away, like Optional, Array, and Dictionary sugar, but
when they do see it it’ll be obvious that it’s a type, and probably obvious
that it’s special because of the “Any”.
>
> - It’s a type; types always start with uppercase letters. (This has been
said plenty by others.)
>
> None of these are particularly strong arguments, I know, and I don’t
have a good alternate suggestion. But I did want to go on record as being
in favor of ‘Any’ and against a binary operator, even though that seems to
put me in the minority.

I suspect that at least part of this is simply greater enthusiasm. I know
I checked out of this thread for a few days while the `&` guys ran rampant.

(P.S. A thought I had just now: If `Any` is our top type, then `All` would
be a good name for our bottom type. And `All<Foo, Bar>` would be a good
"All common supertypes of these types" operation. Both of these came up in
the variadic generics thread, where we were talking about how to create a
type representing any member of a tuple you were trying to splat in.)

--
Brent Royal-Gordon
Architechies

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

I believe it was things like "+" and "-" for set union and subtraction, etc.

-Shawn

···

On Tue, May 24, 2016 at 4:16 PM Matthew Johnson via swift-evolution < swift-evolution@swift.org> wrote:

Sent from my iPad

On May 24, 2016, at 6:09 PM, Brent Royal-Gordon via swift-evolution < > swift-evolution@swift.org> wrote:

>> If we're going to repaint this bikeshed, I think we should also
consider as an alternative some form of infix syntax for composing
constraints. Rust uses `P1 + P2`, and various C++ proposals have suggested
`P1 && P2`.
>
> Given our reluctance to even overload operators for use with Set, I'd
personally find this a bit incongruous.

I don't recall a proposal around operators for Set. What did people want
to use? The obvious candidates are way too hard to type on the keyboards
we have today.

>
> --
> Brent Royal-Gordon
> Architechies
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

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

func foo<X : Collection>(x: X) { ... }

I'm done, sorry.

···

On May 25, 2016, at 1:07 AM, Austin Zheng <austinzheng@gmail.com> wrote:

Because I am bad at typing today, my code examples should read:

foo<X : Collection>(x: X) { ... }

and

let foo : <Collection> = ...

On May 25, 2016, at 1:01 AM, Austin Zheng <austinzheng@gmail.com <mailto:austinzheng@gmail.com>> wrote:

I am not going to comment on the proposal (conflict of interest etc). I do want to speak up in support of Brent's points, though.

On May 25, 2016, at 12:34 AM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

  * What is your evaluation of the proposal?

I am in favor. This is a necessary step towards many future features: class-plus-protocol types, the replacement/reimplementation of AnyObject with Any<class>, existentials with associated types, etc.

One reason to prefer `Any` over `any` which is not listed in the proposal is confusion with the unparameterized `Any` type. Having an uppercase `Any` and a lowercase `any<…>` is going to lead to a lot of confusion; people aren't going to remember whether they need the capitalized form or the lowercase one for any particular use. I don't think we can have `any<...>` unless we're also willing to have an unparameterized `any`, and I think `any` is 100% wrong, because it is absolutely a type but is lowercase.

Since we are trying to cram as many breaking changes as possible into Swift 3, I also think we should consider now, or soon, whether or not we want to draw a strong syntactic line between protocols-as-existentials and protocols-as-constraints by requiring the use of `Any<…>` on all existentials and forbidding its use in constraints. That would mean, for instance, that code like this:

  let printable: CustomStringConvertible = foo

Would now be written:

  let printable: Any<CustomStringConvertible> = foo

I'm sure this will be controversial, but I like the idea of marking all existential types using Any-syntax. It makes the distinction between concrete and existential types in code completely clear to the reader. Given that there are some subtle differences in how concrete and existential types can be used (for example, used as the types of values passed to generic functions), I think this is definitely worth considering.

There are an additional five characters (including two angle brackets to type), but I suspect bare existentials aren't used quite as often as concrete types are, so the aesthetic cost might not be too onerous.

And also that code like:

  func foo<X: Any<Y, Z>>(x: X)

Would probably have to be written something like:

  func foo<X: Y>(x: X) where X: Z

I also personally prefer this convention. The 'Any<Y, Z>' construct in the constraint above does not really have anything to do with existential types as they exist everywhere else in Swift; it simply means that whatever concrete type can be used to instantiate the function must conform to two different protocols.

It's true that any concrete type that could be used to satisfy X in foo() could also be used to fill an Any<Y, Z> existential, but this correspondence isn't interesting to the user. The ways a user can use an Any<Y, Z> existential differ from the ways a sort-of-universal type like X in foo() can be used:

// firstElement's type is known exactly at compile time, because X must be 'filled in'
// by a concrete type, and that concrete type's associated types are also known.
foo<X : Collection>(x: X) {
let firstElement : X.Iterator.Element = x.first!
}

// firstElement's type is not ever known without some sort of dynamic downcasting,
// because the contract that defines the existential can guarantee nothing about its type.
let foo : <X : Collection> = ...
let firstElement : Any = x.first!

However, I believe this would have a significant advantage: it would clarify the distinction between an existential and a constraint. It would more clearly mark where you are taking on the abstraction overhead of an existential. It would also improve the non-existential type situation: in the short term, it would make it clearer where uses of associated type protocols like `Comparable` would not be permitted; in the long term, once we have type-erased existentials for those protocols, it would make it clearer when type erasure was in effect.

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

Yes. `protocol<>` is an ugly and unloved corner of the language; very few people know about it, remember it, or use it. The renaming improves this situation.

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

Given the way it enables many future features, yes.

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

The only language I've used with similar features is Objective-C. There, too, the `<>` is overloaded, now that lightweight generics are part of the language.

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

I'd like to think I have a fairly deep understanding of this feature, having participated heavily in the discussions about it.

--
Brent Royal-Gordon
Architechies

_______________________________________________
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

If we're going to repaint this bikeshed, I think we should also consider as an alternative some form of infix syntax for composing constraints. Rust uses `P1 + P2`, and various C++ proposals have suggested `P1 && P2`.

Given our reluctance to even overload operators for use with Set, I'd personally find this a bit incongruous.

I don't recall a proposal around operators for Set. What did people want to use? The obvious candidates are way too hard to type on the keyboards we have today.

It is a joke, right? The layout of the keyboards used in one country as a driver for a feature.

···

On May 25, 2016, at 1:15 AM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:
On May 24, 2016, at 6:09 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

--
Brent Royal-Gordon
Architechies

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

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

I am not going to comment on the proposal (conflict of interest etc). I do want to speak up in support of Brent's points, though.

  * What is your evaluation of the proposal?

I am in favor. This is a necessary step towards many future features: class-plus-protocol types, the replacement/reimplementation of AnyObject with Any<class>, existentials with associated types, etc.

One reason to prefer `Any` over `any` which is not listed in the proposal is confusion with the unparameterized `Any` type. Having an uppercase `Any` and a lowercase `any<…>` is going to lead to a lot of confusion; people aren't going to remember whether they need the capitalized form or the lowercase one for any particular use. I don't think we can have `any<...>` unless we're also willing to have an unparameterized `any`, and I think `any` is 100% wrong, because it is absolutely a type but is lowercase.

Since we are trying to cram as many breaking changes as possible into Swift 3, I also think we should consider now, or soon, whether or not we want to draw a strong syntactic line between protocols-as-existentials and protocols-as-constraints by requiring the use of `Any<…>` on all existentials and forbidding its use in constraints. That would mean, for instance, that code like this:

  let printable: CustomStringConvertible = foo

Would now be written:

  let printable: Any<CustomStringConvertible> = foo

I'm sure this will be controversial, but I like the idea of marking all existential types using Any-syntax. It makes the distinction between concrete and existential types in code completely clear to the reader. Given that there are some subtle differences in how concrete and existential types can be used (for example, used as the types of values passed to generic functions), I think this is definitely worth considering.

Much of what I read about the swift philosophy seems to boil down to immediate association of the semantic with the syntax, to help the newcomer 'parse' the language in their mind with less efforts. Seems to me that Any<> being so close to Array<> could be construed as running counter to that philosophy.

This is a big part of the case for using lowercase `any`. But there are good arguments on both sides. In Joe’s hypothetical future Swift, `Any` would be a standard library type thus it wouldn’t have such a strong difference from Array.

···

On May 25, 2016, at 9:59 AM, L. Mihalkovic via swift-evolution <swift-evolution@swift.org> wrote:

On May 25, 2016, at 10:01 AM, Austin Zheng via swift-evolution <swift-evolution@swift.org> wrote:

On May 25, 2016, at 12:34 AM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

There are an additional five characters (including two angle brackets to type), but I suspect bare existentials aren't used quite as often as concrete types are, so the aesthetic cost might not be too onerous.

And also that code like:

  func foo<X: Any<Y, Z>>(x: X)

Would probably have to be written something like:

  func foo<X: Y>(x: X) where X: Z

I also personally prefer this convention. The 'Any<Y, Z>' construct in the constraint above does not really have anything to do with existential types as they exist everywhere else in Swift; it simply means that whatever concrete type can be used to instantiate the function must conform to two different protocols.

It's true that any concrete type that could be used to satisfy X in foo() could also be used to fill an Any<Y, Z> existential, but this correspondence isn't interesting to the user. The ways a user can use an Any<Y, Z> existential differ from the ways a sort-of-universal type like X in foo() can be used:

// firstElement's type is known exactly at compile time, because X must be 'filled in'
// by a concrete type, and that concrete type's associated types are also known.
foo<X : Collection>(x: X) {
let firstElement : X.Iterator.Element = x.first!
}

// firstElement's type is not ever known without some sort of dynamic downcasting,
// because the contract that defines the existential can guarantee nothing about its type.
let foo : <X : Collection> = ...
let firstElement : Any = x.first!

However, I believe this would have a significant advantage: it would clarify the distinction between an existential and a constraint. It would more clearly mark where you are taking on the abstraction overhead of an existential. It would also improve the non-existential type situation: in the short term, it would make it clearer where uses of associated type protocols like `Comparable` would not be permitted; in the long term, once we have type-erased existentials for those protocols, it would make it clearer when type erasure was in effect.

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

Yes. `protocol<>` is an ugly and unloved corner of the language; very few people know about it, remember it, or use it. The renaming improves this situation.

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

Given the way it enables many future features, yes.

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

The only language I've used with similar features is Objective-C. There, too, the `<>` is overloaded, now that lightweight generics are part of the language.

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

I'd like to think I have a fairly deep understanding of this feature, having participated heavily in the discussions about it.

--
Brent Royal-Gordon
Architechies

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

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

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

But if we are going to remove the ability to use typealiases bound to `Any` in constraints we need to introduce an alternative mechanism for factoring out constraints (hopefully a superior mechanism that can abstract over constraints that relate generic parameters to each other).

I could certainly imagine having, for instance, a `constraintalias` keyword:

  constraintalias HashableAndComparable = Hashable, Comparable
  constraintalias CollectionOfConforming<ElementConstraint> = Collection where .Element: ElementConstraint

  let value: Any<HashableAndComparable> = 123
  
  func sum<C: CollectionOfConforming<Integer>>(numbers: C) -> C.Iterator.Element {
    return numbers.reduce(0, combine: +)
  }

···

--
Brent Royal-Gordon
Architechies

I am not going to comment on the proposal (conflict of interest etc). I do want to speak up in support of Brent's points, though.

  * What is your evaluation of the proposal?

I am in favor. This is a necessary step towards many future features: class-plus-protocol types, the replacement/reimplementation of AnyObject with Any<class>, existentials with associated types, etc.

One reason to prefer `Any` over `any` which is not listed in the proposal is confusion with the unparameterized `Any` type. Having an uppercase `Any` and a lowercase `any<…>` is going to lead to a lot of confusion; people aren't going to remember whether they need the capitalized form or the lowercase one for any particular use. I don't think we can have `any<...>` unless we're also willing to have an unparameterized `any`, and I think `any` is 100% wrong, because it is absolutely a type but is lowercase.

Since we are trying to cram as many breaking changes as possible into Swift 3, I also think we should consider now, or soon, whether or not we want to draw a strong syntactic line between protocols-as-existentials and protocols-as-constraints by requiring the use of `Any<…>` on all existentials and forbidding its use in constraints. That would mean, for instance, that code like this:

  let printable: CustomStringConvertible = foo

Would now be written:

  let printable: Any<CustomStringConvertible> = foo

I'm sure this will be controversial, but I like the idea of marking all existential types using Any-syntax. It makes the distinction between concrete and existential types in code completely clear to the reader. Given that there are some subtle differences in how concrete and existential types can be used (for example, used as the types of values passed to generic functions), I think this is definitely worth considering.

Much of what I read about the swift philosophy seems to boil down to immediate association of the semantic with the syntax, to help the newcomer 'parse' the language in their mind with less efforts. Seems to me that Any<> being so close to Array<> could be construed as running counter to that philosophy.

This is a big part of the case for using lowercase `any`. But there are good arguments on both sides. In Joe’s hypothetical future Swift, `Any` would be a standard library type thus it wouldn’t have such a strong difference from Array.

I was not referring to Any/Array. I was pointing out the rest of the expressions

Xxxxx<...> versus Yxxxxx<...>

Might not be so easy to explain that despite the similarities of forms, these two expressions are vastly different. Flip side is: if this was scala, it would probably be at every yearly "Swift Days" conference in the "Swift puzzlers" session. :)

···

On May 25, 2016, at 5:03 PM, Matthew Johnson <matthew@anandabits.com> wrote:

On May 25, 2016, at 9:59 AM, L. Mihalkovic via swift-evolution <swift-evolution@swift.org> wrote:
On May 25, 2016, at 10:01 AM, Austin Zheng via swift-evolution <swift-evolution@swift.org> wrote:

On May 25, 2016, at 12:34 AM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

There are an additional five characters (including two angle brackets to type), but I suspect bare existentials aren't used quite as often as concrete types are, so the aesthetic cost might not be too onerous.

And also that code like:

  func foo<X: Any<Y, Z>>(x: X)

Would probably have to be written something like:

  func foo<X: Y>(x: X) where X: Z

I also personally prefer this convention. The 'Any<Y, Z>' construct in the constraint above does not really have anything to do with existential types as they exist everywhere else in Swift; it simply means that whatever concrete type can be used to instantiate the function must conform to two different protocols.

It's true that any concrete type that could be used to satisfy X in foo() could also be used to fill an Any<Y, Z> existential, but this correspondence isn't interesting to the user. The ways a user can use an Any<Y, Z> existential differ from the ways a sort-of-universal type like X in foo() can be used:

// firstElement's type is known exactly at compile time, because X must be 'filled in'
// by a concrete type, and that concrete type's associated types are also known.
foo<X : Collection>(x: X) {
let firstElement : X.Iterator.Element = x.first!
}

// firstElement's type is not ever known without some sort of dynamic downcasting,
// because the contract that defines the existential can guarantee nothing about its type.
let foo : <X : Collection> = ...
let firstElement : Any = x.first!

However, I believe this would have a significant advantage: it would clarify the distinction between an existential and a constraint. It would more clearly mark where you are taking on the abstraction overhead of an existential. It would also improve the non-existential type situation: in the short term, it would make it clearer where uses of associated type protocols like `Comparable` would not be permitted; in the long term, once we have type-erased existentials for those protocols, it would make it clearer when type erasure was in effect.

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

Yes. `protocol<>` is an ugly and unloved corner of the language; very few people know about it, remember it, or use it. The renaming improves this situation.

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

Given the way it enables many future features, yes.

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

The only language I've used with similar features is Objective-C. There, too, the `<>` is overloaded, now that lightweight generics are part of the language.

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

I'd like to think I have a fairly deep understanding of this feature, having participated heavily in the discussions about it.

--
Brent Royal-Gordon
Architechies

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

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

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

The difference stems from the fact that the order of parameters does not matter in `Any` whereas it is essential for generic types.
Would this be changed by Joe’s vision?

-Thorsten

···

Am 25.05.2016 um 17:03 schrieb Matthew Johnson via swift-evolution <swift-evolution@swift.org>:

On May 25, 2016, at 9:59 AM, L. Mihalkovic via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On May 25, 2016, at 10:01 AM, Austin Zheng via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I am not going to comment on the proposal (conflict of interest etc). I do want to speak up in support of Brent's points, though.

On May 25, 2016, at 12:34 AM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

  * What is your evaluation of the proposal?

I am in favor. This is a necessary step towards many future features: class-plus-protocol types, the replacement/reimplementation of AnyObject with Any<class>, existentials with associated types, etc.

One reason to prefer `Any` over `any` which is not listed in the proposal is confusion with the unparameterized `Any` type. Having an uppercase `Any` and a lowercase `any<…>` is going to lead to a lot of confusion; people aren't going to remember whether they need the capitalized form or the lowercase one for any particular use. I don't think we can have `any<...>` unless we're also willing to have an unparameterized `any`, and I think `any` is 100% wrong, because it is absolutely a type but is lowercase.

Since we are trying to cram as many breaking changes as possible into Swift 3, I also think we should consider now, or soon, whether or not we want to draw a strong syntactic line between protocols-as-existentials and protocols-as-constraints by requiring the use of `Any<…>` on all existentials and forbidding its use in constraints. That would mean, for instance, that code like this:

  let printable: CustomStringConvertible = foo

Would now be written:

  let printable: Any<CustomStringConvertible> = foo

I'm sure this will be controversial, but I like the idea of marking all existential types using Any-syntax. It makes the distinction between concrete and existential types in code completely clear to the reader. Given that there are some subtle differences in how concrete and existential types can be used (for example, used as the types of values passed to generic functions), I think this is definitely worth considering.

Much of what I read about the swift philosophy seems to boil down to immediate association of the semantic with the syntax, to help the newcomer 'parse' the language in their mind with less efforts. Seems to me that Any<> being so close to Array<> could be construed as running counter to that philosophy.

This is a big part of the case for using lowercase `any`. But there are good arguments on both sides. In Joe’s hypothetical future Swift, `Any` would be a standard library type thus it wouldn’t have such a strong difference from Array.

After thinking about this topic for the past few days, I'd like to throw in my support for "Any<>" as well. It's one magic construct to learn, looks like a type, has the visual delineation, and shares continuity with both protocol<> and Any today.

I'd also like to express my support for the proposal to delineate generic and existential syntax: all existentials must be written with Any<...>; generic type constraints cannot use it. I hope this will make it clear to people learning and using the language that, despite their superficial similarities, they are actually two different concepts.

I'm neutral on the syntax. But I strongly believe removing the ability to use protocol / Any in generic constraints *must* be accompanied by the introduction of a new (hopefully more robust) mechanism for factoring out common generic constraints.

···

Sent from my iPad

On Jun 1, 2016, at 4:18 PM, Austin Zheng via swift-evolution <swift-evolution@swift.org> wrote:

Austin

On Wed, Jun 1, 2016 at 1:59 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:
> [Proposal: https://github.com/apple/swift-evolution/blob/master/proposals/0095-any-as-existential.md ]
>
> I’m late again to this one, but the discussion’s certainly still going. I’m pretty strongly against the bare ‘A & B’ syntax, for a few reasons:
>
> - Swift doesn’t use ‘&’ for anything except bitwise AND. In particular, it didn’t get picked for set intersection.

I very, *very* much agree with this point. Thus far, Swift has been very conservative about overloading. It seems bizarre that we would violate that policy for these type combinators when much closer matches have been passed over.

I also think that using `&` absolutely *begs* to have an `|` as well, and as much as the Ceylon people clamor for them, I don't think union types make sense in Swift. Unlike Ceylon, Swift uses an algebraic data type for Optional, doesn't use type-erased generics, and supports overloading. As far as I can tell, *none* of the reasons cited in the Ceylon language design FAQ <Eclipse Ceylon™ | projects.eclipse.org; apply to Swift.

(P.S. That language design FAQ is a *fantastic* document.)

> - In theory people are allowed to overload ‘&’ to operate on types. That doesn’t make sense for all types, but you could probably come up with a particular type hierarchy or use of generics where it does make sense.
>
> - I don’t like types with spaces in them when the spaces aren’t bracketed in some way. This is entirely an aesthetic objection, of the form “I don’t naturally read that as a type, or even as a single unit, when looking at code.” This isn’t a great objection because someone could have said it about `[Int]` or `Int?` as well. (It would be a more realistic objection if some of our brackets weren’t “<" and “>”.)

To augment this: I think that if we're going to see a lot of little `where` clauses attached to types, you kind of have to have a bracketing syntax to put them in. And no, `(Collection where .Element == String)` doesn't count. `()` is about precedence, and this isn't a question of precedence; it's a question of making the type read as a single unit.

> And I still support the ‘Any’ syntax, despite the “order doesn’t matter” problem:
>
> - It’s consistent with the existing unconstrained ‘Any’ and with the current dedicated wrapper types. If we didn’t think it was a good name for those, we wouldn’t use it there either.

One of my concerns with the `&` syntax is that it leaves no good way to define `Any`. I don't like having a magic `&` operator *and* a magic `Any` keyword, neither of which derives from anything more general.

> - It’s easily learnable. It’s rare enough that someone wouldn’t be exposed to it right away, like Optional, Array, and Dictionary sugar, but when they do see it it’ll be obvious that it’s a type, and probably obvious that it’s special because of the “Any”.
>
> - It’s a type; types always start with uppercase letters. (This has been said plenty by others.)
>
> None of these are particularly strong arguments, I know, and I don’t have a good alternate suggestion. But I did want to go on record as being in favor of ‘Any’ and against a binary operator, even though that seems to put me in the minority.

I suspect that at least part of this is simply greater enthusiasm. I know I checked out of this thread for a few days while the `&` guys ran rampant.

(P.S. A thought I had just now: If `Any` is our top type, then `All` would be a good name for our bottom type. And `All<Foo, Bar>` would be a good "All common supertypes of these types" operation. Both of these came up in the variadic generics thread, where we were talking about how to create a type representing any member of a tuple you were trying to splat in.)

--
Brent Royal-Gordon
Architechies

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

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

This is definitely getting off-topic for this particular review, but I’ve come to agree with you. I can only speak for myself, but back when we were implementing protocols in Swift it felt great to eliminate the wedge between ’NSTableView *’ and ‘id <NSTableViewDelegate>’. But then we started using protocols for many more things in Swift, and it turns out that the simple use case of “I have a protocol-typed property” isn’t really the one worth optimizing for anymore. When they’re arguments, you more often than not might want to use them generically, and you should at least be thinking about that when you define a function.

Where we are today, the protocol-typed value is the obvious choice, and then you move to generics when the compiler tells you no. Having the choice be between these two:

func foo<T: SignedInteger>(value: T)
func foo(value: Any<SignedInteger>)

makes it a little more likely that someone will stop and think about picking the first.

(Then again, Joe’s talked about making the second use the ABI of the first anyway as an optimization, though that can backfire if the value is copied around a lot.)

I suppose a middle ground would restrict the protocol-name-only syntax to class-bound protocols, which are the most likely to be used in properties (“delegate-like protocols”). I’d be hesitant to restrict to “class-bound protocols without associated types” because we want adding an associated type to be a non-breaking change <http://jrose-apple.github.io/swift-library-evolution/#protocols&gt; (if we can figure out how to do it).

Jordan

···

On Jun 1, 2016, at 14:18, Austin Zheng <austinzheng@gmail.com> wrote:

I'd also like to express my support for the proposal to delineate generic and existential syntax: all existentials must be written with Any<...>; generic type constraints cannot use it. I hope this will make it clear to people learning and using the language that, despite their superficial similarities, they are actually two different concepts.

I believe it was things like "+" and "-" for set union and subtraction, etc.

That, or &, |, and ^, by analogy with bitwise operators. It definitely came up during the SetAlgebra discussions.

···

--
Brent Royal-Gordon
Sent from my iPhone

I believe it was things like "+" and "-" for set union and subtraction, etc.

That, or &, |, and ^, by analogy with bitwise operators. It definitely came up during the SetAlgebra discussions.

Another thread I guess I didn’t follow closely enough. I think I agree with avoiding using unconventional operators for operations which already have conventional operators associated with them. Maybe someday it will be easy enough to type unicode operators that it might be reasonable to think about using them.

···

On May 24, 2016, at 7:45 PM, Brent Royal-Gordon <brent@architechies.com> wrote:

--
Brent Royal-Gordon
Sent from my iPhone

Kinda off-topic, but since you asked… I’m a fan of using a custom keyboard layout to remap the alt-layer (http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=ukelele\). There’s also the “Greek Polytonic” layout included in OS X which has several of math symbols, but notably not anything from set notation. You'd still need a custom layout for those, or just keep the “emoji & symbols” viewer up.

Unicode isn't hard to do (at least on OS X… I haven’t tried Windows or Linux), but it’s impossible to make a class-compliant keyboard that just directly types unicode characters because the USB HID spec doesn’t support it (Issues · kiibohd/KiiConf · GitHub). Until that changes, we’re stuck with using either custom keyboard layouts, macro software, or app-dependant shortcuts. It’s not impossible, it just takes a few of the 800+ member companies deciding that it’s time to get the ball rolling. If only someone who works for such a company were on this mailing list...

- Dave Sweeris

···

On May 24, 2016, at 8:06 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

On May 24, 2016, at 7:45 PM, Brent Royal-Gordon <brent@architechies.com <mailto:brent@architechies.com>> wrote:

I believe it was things like "+" and "-" for set union and subtraction, etc.

That, or &, |, and ^, by analogy with bitwise operators. It definitely came up during the SetAlgebra discussions.

Another thread I guess I didn’t follow closely enough. I think I agree with avoiding using unconventional operators for operations which already have conventional operators associated with them. Maybe someday it will be easy enough to type unicode operators that it might be reasonable to think about using them.

Sent from my iPad

If we're going to repaint this bikeshed, I think we should also consider as an alternative some form of infix syntax for composing constraints. Rust uses `P1 + P2`, and various C++ proposals have suggested `P1 && P2`.

Given our reluctance to even overload operators for use with Set, I'd personally find this a bit incongruous.

I don't recall a proposal around operators for Set. What did people want to use? The obvious candidates are way too hard to type on the keyboards we have today.

It is a joke, right? The layout of the keyboards used in one country as a driver for a feature.

I'm thinking of keyboards much different than we have today. Imagine a keyboard where the meaning of keys isn't fixed, but is instead controllable by apps. This may, but need not be a touchscreen keyboard like we have on iPad. There are hardware keyboards with physical keys where each key displays a software provided symbol. If keyboards lie this become ubiquitous it would be easy for programming apps to make Unicode operator symbols relatively easy for everyone to type, regardless of locale.

···

Sent from my iPad

On May 25, 2016, at 1:33 AM, L. Mihalkovic <laurent.mihalkovic@gmail.com> wrote:

On May 25, 2016, at 1:15 AM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:
On May 24, 2016, at 6:09 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

--
Brent Royal-Gordon
Architechies

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

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

If we're going to repaint this bikeshed, I think we should also consider as an alternative some form of infix syntax for composing constraints. Rust uses `P1 + P2`, and various C++ proposals have suggested `P1 && P2`.

Given our reluctance to even overload operators for use with Set, I'd personally find this a bit incongruous.

I don't recall a proposal around operators for Set. What did people want to use? The obvious candidates are way too hard to type on the keyboards we have today.

It is a joke, right? The layout of the keyboards used in one country as a driver for a feature.

I was a bit in shock when I saw this:

https://github.com/apple/swift/blob/master/stdlib/internal/SwiftExperimental/SwiftExperimental.swift

I know it's marked experimental, but wow... It looks pretty, but it's insane and IMHO something that shouldn't be in the standard lib's master branch.

I am not going to comment on the proposal (conflict of interest etc). I do want to speak up in support of Brent's points, though.

  * What is your evaluation of the proposal?

I am in favor. This is a necessary step towards many future features: class-plus-protocol types, the replacement/reimplementation of AnyObject with Any<class>, existentials with associated types, etc.

One reason to prefer `Any` over `any` which is not listed in the proposal is confusion with the unparameterized `Any` type. Having an uppercase `Any` and a lowercase `any<…>` is going to lead to a lot of confusion; people aren't going to remember whether they need the capitalized form or the lowercase one for any particular use. I don't think we can have `any<...>` unless we're also willing to have an unparameterized `any`, and I think `any` is 100% wrong, because it is absolutely a type but is lowercase.

Since we are trying to cram as many breaking changes as possible into Swift 3, I also think we should consider now, or soon, whether or not we want to draw a strong syntactic line between protocols-as-existentials and protocols-as-constraints by requiring the use of `Any<…>` on all existentials and forbidding its use in constraints. That would mean, for instance, that code like this:

  let printable: CustomStringConvertible = foo

Would now be written:

  let printable: Any<CustomStringConvertible> = foo

I'm sure this will be controversial, but I like the idea of marking all existential types using Any-syntax. It makes the distinction between concrete and existential types in code completely clear to the reader. Given that there are some subtle differences in how concrete and existential types can be used (for example, used as the types of values passed to generic functions), I think this is definitely worth considering.

Much of what I read about the swift philosophy seems to boil down to immediate association of the semantic with the syntax, to help the newcomer 'parse' the language in their mind with less efforts. Seems to me that Any<> being so close to Array<> could be construed as running counter to that philosophy.

This is a big part of the case for using lowercase `any`. But there are good arguments on both sides. In Joe’s hypothetical future Swift, `Any` would be a standard library type thus it wouldn’t have such a strong difference from Array.

I was not referring to Any/Array. I was pointing out the rest of the expressions

Xxxxx<...> versus Yxxxxx<...>

Might not be so easy to explain that despite the similarities of forms, these two expressions are vastly different. Flip side is: if this was scala, it would probably be at every yearly "Swift Days" conference in the "Swift puzzlers" session. :)

You are referring to the fact that `any` is not a generic type and that is the source of its different behavior, aren’t you? If not, can you clarify what you mean?

If so, my point was that if it eventually becomes possible to write such constructs in a library as in Joe’s example:

A few people have also noted the similarity between Any<...> and normal generic types. This is potentially confusing today, but with enough magic language features from the future, Any *could* conceivably be made a library feature in the fullness of time:

  // Let's say 'protocol' constraints indicate second-order constraint variables:
  enum Any<Constraints: protocol> {
    // And we have GADTs:
    case value<T: Constraints>(T)
  }

  // And we have user-defined value subtyping:
  extension <Constraints: protocol, T: Constraints> T: Any<Constraints> { … }

The distinction loses its power. Users can write other things that have similar behavior to `Any`. In that world uppercase makes sense as the naming convention. I don’t think we would want to use lowercase for all similar user-defined constructs.

···

On May 25, 2016, at 10:28 AM, L. Mihalkovic <laurent.mihalkovic@gmail.com> wrote:
On May 25, 2016, at 5:03 PM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

On May 25, 2016, at 9:59 AM, L. Mihalkovic via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On May 25, 2016, at 10:01 AM, Austin Zheng via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On May 25, 2016, at 12:34 AM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

There are an additional five characters (including two angle brackets to type), but I suspect bare existentials aren't used quite as often as concrete types are, so the aesthetic cost might not be too onerous.

And also that code like:

  func foo<X: Any<Y, Z>>(x: X)

Would probably have to be written something like:

  func foo<X: Y>(x: X) where X: Z

I also personally prefer this convention. The 'Any<Y, Z>' construct in the constraint above does not really have anything to do with existential types as they exist everywhere else in Swift; it simply means that whatever concrete type can be used to instantiate the function must conform to two different protocols.

It's true that any concrete type that could be used to satisfy X in foo() could also be used to fill an Any<Y, Z> existential, but this correspondence isn't interesting to the user. The ways a user can use an Any<Y, Z> existential differ from the ways a sort-of-universal type like X in foo() can be used:

// firstElement's type is known exactly at compile time, because X must be 'filled in'
// by a concrete type, and that concrete type's associated types are also known.
foo<X : Collection>(x: X) {
let firstElement : X.Iterator.Element = x.first!
}

// firstElement's type is not ever known without some sort of dynamic downcasting,
// because the contract that defines the existential can guarantee nothing about its type.
let foo : <X : Collection> = ...
let firstElement : Any = x.first!

However, I believe this would have a significant advantage: it would clarify the distinction between an existential and a constraint. It would more clearly mark where you are taking on the abstraction overhead of an existential. It would also improve the non-existential type situation: in the short term, it would make it clearer where uses of associated type protocols like `Comparable` would not be permitted; in the long term, once we have type-erased existentials for those protocols, it would make it clearer when type erasure was in effect.

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

Yes. `protocol<>` is an ugly and unloved corner of the language; very few people know about it, remember it, or use it. The renaming improves this situation.

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

Given the way it enables many future features, yes.

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

The only language I've used with similar features is Objective-C. There, too, the `<>` is overloaded, now that lightweight generics are part of the language.

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

I'd like to think I have a fairly deep understanding of this feature, having participated heavily in the discussions about it.

--
Brent Royal-Gordon
Architechies

_______________________________________________
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