[Proposal] Separate protocols and interfaces


(Anton Zhilin) #1

Introduction of interfaces will clean up the current blend of static and
dynamic protocols, and solve at least three popular issues.
Please see:
https://github.com/Anton3/swift-evolution/blob/master/proposals/0000-introducing-interfaces.md


(David Waite) #2

I like this, and had considered proposing something similar.

Points:
I would have chose to leave protocol to mean the dynamically dispatch-able type declaration, as that is what it indicates in Objective-C. Your proposal would cause every Objective-C protocol to now be considered an interface in Swift terms.

Some discussion on this list makes me think that you might instead have a modifier for declaring statically dispatched, existential protocols - e.g. “existential protocol SequenceType { … }”

Also, note not all usage of Self need be disallowed in dynamically dispatch-able types today:

protocol Test {
     func foo() -> Self
}

var t:Test? // legal, I assume on purpose due to the covariance of the return type

-DW

···

On Jan 3, 2016, at 7:48 AM, Антон Жилин via swift-evolution <swift-evolution@swift.org> wrote:

Introduction of interfaces will clean up the current blend of static and dynamic protocols, and solve at least three popular issues.
Please see:
https://github.com/Anton3/swift-evolution/blob/master/proposals/0000-introducing-interfaces.md _______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Matthew Johnson) #3

I like this, and had considered proposing something similar.

Points:
I would have chose to leave protocol to mean the dynamically dispatch-able type declaration, as that is what it indicates in Objective-C. Your proposal would cause every Objective-C protocol to now be considered an interface in Swift terms.

Some discussion on this list makes me think that you might instead have a modifier for declaring statically dispatched, existential protocols - e.g. “existential protocol SequenceType { … }”

The problem with *requiring* distinct syntax for protocols that are intended to be used as existential a is that it is a stated goal to expand the kinds of protocols which can be used as existentials. In other words, the set of protocols that can be used as existentials is a moving target that is likely to grow substantially in the future.

I would be comfortable with some kind of optional assertion that a protocol can be used as an existential but probably not comfortable with anything more than that.

···

Sent from my iPad

On Jan 3, 2016, at 10:53 AM, David Waite via swift-evolution <swift-evolution@swift.org> wrote:

Also, note not all usage of Self need be disallowed in dynamically dispatch-able types today:

protocol Test {
     func foo() -> Self
}

var t:Test? // legal, I assume on purpose due to the covariance of the return type

-DW

On Jan 3, 2016, at 7:48 AM, Антон Жилин via swift-evolution <swift-evolution@swift.org> wrote:

Introduction of interfaces will clean up the current blend of static and dynamic protocols, and solve at least three popular issues.
Please see:
https://github.com/Anton3/swift-evolution/blob/master/proposals/0000-introducing-interfaces.md
_______________________________________________
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


(Douglas Gregor) #4

I am *completely* against this proposal.

Fundamentally, you're trying to address the limitation that protocols with Self or associated type requirements can't be existential. But it's just a limitation that isn't (conceptually) that hard to fix: the primary operation you need to work with an existing of such a protocol is to "open" a value of existential type, giving a name to the dynamic type it stores. Let's invent one:

  func eq(x: Equatable, y: Equatable) -> Bool {
    // give the name T to the dynamic type stored in xT
    let xT = open x as T
    // is y also storing a T?
    guard let yT = y as? T else { return false }
    // check whether the Ts are equal
    return xT == yT
  }

Ignore the syntax: semantically, we've gone from a "dynamic" existential thing back to something more "static", just by giving a name to the type. Swift generics aren't really even static in any sense: what the do is give names to the types of values so one can establish relationships among different values. "open..as" would do that for existentials.

Note that ether Swift compilers AST and SIL both have "open existential" operations that do this internally. They have no spelling in Swift code, but they are useful to describe operations on existentials. At present, they cannot be formed when the existential involves a protocol with Self or associated type requirements, but that's a limitation that isn't hard to address.

As for your concerns about knowing when one can dynamically override and when one cannot... There are issues here that need to be addressed. They aren't significant enough to warrant such a drastic change, and may not even require language changes at all.

  - Doug

···

On Jan 3, 2016, at 6:48 AM, Антон Жилин via swift-evolution <swift-evolution@swift.org> wrote:

Introduction of interfaces will clean up the current blend of static and dynamic protocols, and solve at least three popular issues.
Please see:
https://github.com/Anton3/swift-evolution/blob/master/proposals/0000-introducing-interfaces.md


(David Waite) #5

This would be wonderful - is it something that could happen in the Swift 3 timeframe? Is it something that myself or someone else could work on a formal proposal for?

-DW

···

On Jan 3, 2016, at 4:17 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 3, 2016, at 6:48 AM, Антон Жилин via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Introduction of interfaces will clean up the current blend of static and dynamic protocols, and solve at least three popular issues.
Please see:
https://github.com/Anton3/swift-evolution/blob/master/proposals/0000-introducing-interfaces.md

I am *completely* against this proposal.

Fundamentally, you're trying to address the limitation that protocols with Self or associated type requirements can't be existential. But it's just a limitation that isn't (conceptually) that hard to fix: the primary operation you need to work with an existing of such a protocol is to "open" a value of existential type, giving a name to the dynamic type it stores. Let's invent one:

  func eq(x: Equatable, y: Equatable) -> Bool {
    // give the name T to the dynamic type stored in xT
    let xT = open x as T
    // is y also storing a T?
    guard let yT = y as? T else { return false }
    // check whether the Ts are equal
    return xT == yT
  }

Ignore the syntax: semantically, we've gone from a "dynamic" existential thing back to something more "static", just by giving a name to the type. Swift generics aren't really even static in any sense: what the do is give names to the types of values so one can establish relationships among different values. "open..as" would do that for existentials.

Note that ether Swift compilers AST and SIL both have "open existential" operations that do this internally. They have no spelling in Swift code, but they are useful to describe operations on existentials. At present, they cannot be formed when the existential involves a protocol with Self or associated type requirements, but that's a limitation that isn't hard to address.

As for your concerns about knowing when one can dynamically override and when one cannot... There are issues here that need to be addressed. They aren't significant enough to warrant such a drastic change, and may not even require language changes at all.

  - Doug

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


(Austin Zheng) #6

+1 to "opening" values of existential type, I remember trying (and failing)
to do this when Swift 1 came out. Being able to capture the dynamic type of
an object at runtime and do stuff with it would be incredible.

Austin

···

On Sun, Jan 3, 2016 at 4:19 PM, David Waite via swift-evolution < swift-evolution@swift.org> wrote:

This would be wonderful - is it something that could happen in the Swift 3
timeframe? Is it something that myself or someone else could work on a
formal proposal for?

-DW

On Jan 3, 2016, at 4:17 PM, Douglas Gregor via swift-evolution < > swift-evolution@swift.org> wrote:

On Jan 3, 2016, at 6:48 AM, Антон Жилин via swift-evolution < > swift-evolution@swift.org> wrote:

Introduction of interfaces will clean up the current blend of static and
dynamic protocols, and solve at least three popular issues.
Please see:

https://github.com/Anton3/swift-evolution/blob/master/proposals/0000-introducing-interfaces.md

I am *completely* against this proposal.

Fundamentally, you're trying to address the limitation that protocols with
Self or associated type requirements can't be existential. But it's just a
limitation that isn't (conceptually) that hard to fix: the primary
operation you need to work with an existing of such a protocol is to "open"
a value of existential type, giving a name to the dynamic type it stores.
Let's invent one:

  func eq(x: Equatable, y: Equatable) -> Bool {
    // give the name T to the dynamic type stored in xT
    let xT = open x as T
    // is y also storing a T?
    guard let yT = y as? T else { return false }
    // check whether the Ts are equal
    return xT == yT
  }

Ignore the syntax: semantically, we've gone from a "dynamic" existential
thing back to something more "static", just by giving a name to the type.
Swift generics aren't really even static in any sense: what the do is give
names to the types of values so one can establish relationships among
different values. "open..as" would do that for existentials.

Note that ether Swift compilers AST and SIL both have "open existential"
operations that do this internally. They have no spelling in Swift code,
but they are useful to describe operations on existentials. At present,
they cannot be formed when the existential involves a protocol with Self or
associated type requirements, but that's a limitation that isn't hard to
address.

As for your concerns about knowing when one can dynamically override and
when one cannot... There are issues here that need to be addressed. They
aren't significant enough to warrant such a drastic change, and may not
even require language changes at all.

- Doug

_______________________________________________
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


(Drew Crawford) #7

I offer a +1, but I have two criticisms of the proposal.

The first is that the example given in the proposal is stated a lot more strongly than is true:

func compareTwo(first: Comparable, _ second: Comparable) -> Int { // error!
  if first < second {
    return -1
  }
  //...
}
The code above yields an error, and rightfully so, because if the real types of first and second are not equal, they cannot actually be compared.

It is true for Swift 2 code. However, whether this is true forever is less clear. There is a thread here discussing "existential protocols", which AFAIK would make this code listing into a non-error, and in that thread Douglas Gregor said:

Do recall that I’m saying “not now” rather than “not ever” for this feature. I think it’s very, very cool, but it’s complicated and we need a while to understand its overall effects.

As long as the door is open to allowing the syntax, I think saying something strong and normative about it in an official proposal would be a mistake. The example is fine, but the comment should be that this "currently errors" or "surprises new programmers" or something weaker than "it's obvious to all of us this shouldn't work" because it's obvious to some people that it should work after all.

The second thing is that I think using the words "dynamically dispatched" or "dynamically dispatched interfaces" in the body of the proposal is a mistake. It is not that interfaces "are" dynamically dispatched. It is that they may be, e.g. that the compiler may select a dynamic implementation (or it may be able to find a static implementation), whereas for a protocol the compiler is guaranteed to use a static implementation. This is I think more consistent with CL's position on static/dynamic in Swift <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/001948.html> generally. So I think we should find a turn of phrase like "behaves dynamically" or "has dynamic dispatch semantics" rather than saying "it *is* dynamically dispatched" as if we will force the optimizer to spit out a vtable when it can find a static implementation.

With those two details resolved I think it is a strong proposal, and very much in line with the proposal we're reviewing about separating typealias vs associatedtype, which strikes at a similar confusion where we're separating two different concepts into their own keywords.

···

On Jan 3, 2016, at 7:44 PM, Austin Zheng via swift-evolution <swift-evolution@swift.org> wrote:

+1 to "opening" values of existential type, I remember trying (and failing) to do this when Swift 1 came out. Being able to capture the dynamic type of an object at runtime and do stuff with it would be incredible.

Austin

On Sun, Jan 3, 2016 at 4:19 PM, David Waite via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
This would be wonderful - is it something that could happen in the Swift 3 timeframe? Is it something that myself or someone else could work on a formal proposal for?

-DW

On Jan 3, 2016, at 4:17 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jan 3, 2016, at 6:48 AM, Антон Жилин via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Introduction of interfaces will clean up the current blend of static and dynamic protocols, and solve at least three popular issues.
Please see:
https://github.com/Anton3/swift-evolution/blob/master/proposals/0000-introducing-interfaces.md

I am *completely* against this proposal.

Fundamentally, you're trying to address the limitation that protocols with Self or associated type requirements can't be existential. But it's just a limitation that isn't (conceptually) that hard to fix: the primary operation you need to work with an existing of such a protocol is to "open" a value of existential type, giving a name to the dynamic type it stores. Let's invent one:

  func eq(x: Equatable, y: Equatable) -> Bool {
    // give the name T to the dynamic type stored in xT
    let xT = open x as T
    // is y also storing a T?
    guard let yT = y as? T else { return false }
    // check whether the Ts are equal
    return xT == yT
  }

Ignore the syntax: semantically, we've gone from a "dynamic" existential thing back to something more "static", just by giving a name to the type. Swift generics aren't really even static in any sense: what the do is give names to the types of values so one can establish relationships among different values. "open..as" would do that for existentials.

Note that ether Swift compilers AST and SIL both have "open existential" operations that do this internally. They have no spelling in Swift code, but they are useful to describe operations on existentials. At present, they cannot be formed when the existential involves a protocol with Self or associated type requirements, but that's a limitation that isn't hard to address.

As for your concerns about knowing when one can dynamically override and when one cannot... There are issues here that need to be addressed. They aren't significant enough to warrant such a drastic change, and may not even require language changes at all.

  - Doug

_______________________________________________
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


(Douglas Gregor) #8

This would be wonderful - is it something that could happen in the Swift 3 timeframe?

I hesitate to say “yes” here. I think it fits with the goals of Swift 3, but my main concern is that there isn’t enough engineering bandwidth to implement it for Swift 3.

Is it something that myself or someone else could work on a formal proposal for?

Yes, absolutely. This is a case where I think it’s useful to design what we want, even if we cannot fit the implementation into the Swift 3 schedule. It’s also a case where the compiler has a lot of the pieces already implemented (with some runtime bits landing soon), so the implementation should not be *that* hard and will likely not require architectural changes.

  - Doug

···

On Jan 3, 2016, at 4:19 PM, David Waite <david@alkaline-solutions.com> wrote:

-DW

On Jan 3, 2016, at 4:17 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jan 3, 2016, at 6:48 AM, Антон Жилин via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Introduction of interfaces will clean up the current blend of static and dynamic protocols, and solve at least three popular issues.
Please see:
https://github.com/Anton3/swift-evolution/blob/master/proposals/0000-introducing-interfaces.md

I am *completely* against this proposal.

Fundamentally, you're trying to address the limitation that protocols with Self or associated type requirements can't be existential. But it's just a limitation that isn't (conceptually) that hard to fix: the primary operation you need to work with an existing of such a protocol is to "open" a value of existential type, giving a name to the dynamic type it stores. Let's invent one:

  func eq(x: Equatable, y: Equatable) -> Bool {
    // give the name T to the dynamic type stored in xT
    let xT = open x as T
    // is y also storing a T?
    guard let yT = y as? T else { return false }
    // check whether the Ts are equal
    return xT == yT
  }

Ignore the syntax: semantically, we've gone from a "dynamic" existential thing back to something more "static", just by giving a name to the type. Swift generics aren't really even static in any sense: what the do is give names to the types of values so one can establish relationships among different values. "open..as" would do that for existentials.

Note that ether Swift compilers AST and SIL both have "open existential" operations that do this internally. They have no spelling in Swift code, but they are useful to describe operations on existentials. At present, they cannot be formed when the existential involves a protocol with Self or associated type requirements, but that's a limitation that isn't hard to address.

As for your concerns about knowing when one can dynamically override and when one cannot... There are issues here that need to be addressed. They aren't significant enough to warrant such a drastic change, and may not even require language changes at all.

  - Doug

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


(Matthew Johnson) #9

I offer a +1, but I have two criticisms of the proposal.

The first is that the example given in the proposal is stated a lot more strongly than is true:

func compareTwo(first: Comparable, _ second: Comparable) -> Int { // error!
  if first < second {
    return -1
  }
  //...
}
The code above yields an error, and rightfully so, because if the real types of first and second are not equal, they cannot actually be compared.

It is true for Swift 2 code. However, whether this is true forever is less clear. There is a thread here discussing "existential protocols", which AFAIK would make this code listing into a non-error, and in that thread Douglas Gregor said:

Do recall that I’m saying “not now” rather than “not ever” for this feature. I think it’s very, very cool, but it’s complicated and we need a while to understand its overall effects.

Existentials for protocols with Self and / or associated type requirements would require bindings for Self and / or the associated type(s). At least when you use a member that contains Self and / or an associated type in its signature. So the previous example will always fail to compile.

···

On Jan 3, 2016, at 8:52 PM, Drew Crawford via swift-evolution <swift-evolution@swift.org> wrote:

As long as the door is open to allowing the syntax, I think saying something strong and normative about it in an official proposal would be a mistake. The example is fine, but the comment should be that this "currently errors" or "surprises new programmers" or something weaker than "it's obvious to all of us this shouldn't work" because it's obvious to some people that it should work after all.

The second thing is that I think using the words "dynamically dispatched" or "dynamically dispatched interfaces" in the body of the proposal is a mistake. It is not that interfaces "are" dynamically dispatched. It is that they may be, e.g. that the compiler may select a dynamic implementation (or it may be able to find a static implementation), whereas for a protocol the compiler is guaranteed to use a static implementation. This is I think more consistent with CL's position on static/dynamic in Swift <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/001948.html> generally. So I think we should find a turn of phrase like "behaves dynamically" or "has dynamic dispatch semantics" rather than saying "it *is* dynamically dispatched" as if we will force the optimizer to spit out a vtable when it can find a static implementation.

With those two details resolved I think it is a strong proposal, and very much in line with the proposal we're reviewing about separating typealias vs associatedtype, which strikes at a similar confusion where we're separating two different concepts into their own keywords.

On Jan 3, 2016, at 7:44 PM, Austin Zheng via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

+1 to "opening" values of existential type, I remember trying (and failing) to do this when Swift 1 came out. Being able to capture the dynamic type of an object at runtime and do stuff with it would be incredible.

Austin

On Sun, Jan 3, 2016 at 4:19 PM, David Waite via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
This would be wonderful - is it something that could happen in the Swift 3 timeframe? Is it something that myself or someone else could work on a formal proposal for?

-DW

On Jan 3, 2016, at 4:17 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jan 3, 2016, at 6:48 AM, Антон Жилин via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Introduction of interfaces will clean up the current blend of static and dynamic protocols, and solve at least three popular issues.
Please see:
https://github.com/Anton3/swift-evolution/blob/master/proposals/0000-introducing-interfaces.md

I am *completely* against this proposal.

Fundamentally, you're trying to address the limitation that protocols with Self or associated type requirements can't be existential. But it's just a limitation that isn't (conceptually) that hard to fix: the primary operation you need to work with an existing of such a protocol is to "open" a value of existential type, giving a name to the dynamic type it stores. Let's invent one:

  func eq(x: Equatable, y: Equatable) -> Bool {
    // give the name T to the dynamic type stored in xT
    let xT = open x as T
    // is y also storing a T?
    guard let yT = y as? T else { return false }
    // check whether the Ts are equal
    return xT == yT
  }

Ignore the syntax: semantically, we've gone from a "dynamic" existential thing back to something more "static", just by giving a name to the type. Swift generics aren't really even static in any sense: what the do is give names to the types of values so one can establish relationships among different values. "open..as" would do that for existentials.

Note that ether Swift compilers AST and SIL both have "open existential" operations that do this internally. They have no spelling in Swift code, but they are useful to describe operations on existentials. At present, they cannot be formed when the existential involves a protocol with Self or associated type requirements, but that's a limitation that isn't hard to address.

As for your concerns about knowing when one can dynamically override and when one cannot... There are issues here that need to be addressed. They aren't significant enough to warrant such a drastic change, and may not even require language changes at all.

  - Doug

_______________________________________________
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


(Goffredo Marocchi) #10

In his message Chris stated that protocols are obviously dynamic while in the case of protocol extensions we have default implementations (IMHO out of place in protocols if we see protocols are pure abstract contracts designed to decouple from the actual implementation) and the compiler will use a static implementation just because of the dressing/the type our object is casted as. It just feels wrong and an indication that we are now leaking implementation details we were trying to hide.

I think this is a compiler optimisation which should not be implicitly applied unless it has side effects and this example shows one of those side effects. In such cases, I think we should have a keyword to override the compiler with and strongly hint we want to enforce the compiler to use the static implementation.

···

Sent from my iPhone

On 4 Jan 2016, at 02:52, Drew Crawford via swift-evolution <swift-evolution@swift.org> wrote:

I offer a +1, but I have two criticisms of the proposal.

The first is that the example given in the proposal is stated a lot more strongly than is true:

func compareTwo(first: Comparable, _ second: Comparable) -> Int { // error!
  if first < second {
    return -1
  }
  //...
}
The code above yields an error, and rightfully so, because if the real types of first and second are not equal, they cannot actually be compared.

It is true for Swift 2 code. However, whether this is true forever is less clear. There is a thread here discussing "existential protocols", which AFAIK would make this code listing into a non-error, and in that thread Douglas Gregor said:

Do recall that I’m saying “not now” rather than “not ever” for this feature. I think it’s very, very cool, but it’s complicated and we need a while to understand its overall effects.

As long as the door is open to allowing the syntax, I think saying something strong and normative about it in an official proposal would be a mistake. The example is fine, but the comment should be that this "currently errors" or "surprises new programmers" or something weaker than "it's obvious to all of us this shouldn't work" because it's obvious to some people that it should work after all.

The second thing is that I think using the words "dynamically dispatched" or "dynamically dispatched interfaces" in the body of the proposal is a mistake. It is not that interfaces "are" dynamically dispatched. It is that they may be, e.g. that the compiler may select a dynamic implementation (or it may be able to find a static implementation), whereas for a protocol the compiler is guaranteed to use a static implementation. This is I think more consistent with CL's position on static/dynamic in Swift generally. So I think we should find a turn of phrase like "behaves dynamically" or "has dynamic dispatch semantics" rather than saying "it *is* dynamically dispatched" as if we will force the optimizer to spit out a vtable when it can find a static implementation.

With those two details resolved I think it is a strong proposal, and very much in line with the proposal we're reviewing about separating typealias vs associatedtype, which strikes at a similar confusion where we're separating two different concepts into their own keywords.

On Jan 3, 2016, at 7:44 PM, Austin Zheng via swift-evolution <swift-evolution@swift.org> wrote:

+1 to "opening" values of existential type, I remember trying (and failing) to do this when Swift 1 came out. Being able to capture the dynamic type of an object at runtime and do stuff with it would be incredible.

Austin

On Sun, Jan 3, 2016 at 4:19 PM, David Waite via swift-evolution <swift-evolution@swift.org> wrote:
This would be wonderful - is it something that could happen in the Swift 3 timeframe? Is it something that myself or someone else could work on a formal proposal for?

-DW

On Jan 3, 2016, at 4:17 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 3, 2016, at 6:48 AM, Антон Жилин via swift-evolution <swift-evolution@swift.org> wrote:

Introduction of interfaces will clean up the current blend of static and dynamic protocols, and solve at least three popular issues.
Please see:
https://github.com/Anton3/swift-evolution/blob/master/proposals/0000-introducing-interfaces.md

I am *completely* against this proposal.

Fundamentally, you're trying to address the limitation that protocols with Self or associated type requirements can't be existential. But it's just a limitation that isn't (conceptually) that hard to fix: the primary operation you need to work with an existing of such a protocol is to "open" a value of existential type, giving a name to the dynamic type it stores. Let's invent one:

  func eq(x: Equatable, y: Equatable) -> Bool {
    // give the name T to the dynamic type stored in xT
    let xT = open x as T
    // is y also storing a T?
    guard let yT = y as? T else { return false }
    // check whether the Ts are equal
    return xT == yT
  }

Ignore the syntax: semantically, we've gone from a "dynamic" existential thing back to something more "static", just by giving a name to the type. Swift generics aren't really even static in any sense: what the do is give names to the types of values so one can establish relationships among different values. "open..as" would do that for existentials.

Note that ether Swift compilers AST and SIL both have "open existential" operations that do this internally. They have no spelling in Swift code, but they are useful to describe operations on existentials. At present, they cannot be formed when the existential involves a protocol with Self or associated type requirements, but that's a limitation that isn't hard to address.

As for your concerns about knowing when one can dynamically override and when one cannot... There are issues here that need to be addressed. They aren't significant enough to warrant such a drastic change, and may not even require language changes at all.

  - Doug

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

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

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

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


(Matthew Johnson) #11

This would be wonderful - is it something that could happen in the Swift 3 timeframe?

I hesitate to say “yes” here. I think it fits with the goals of Swift 3, but my main concern is that there isn’t enough engineering bandwidth to implement it for Swift 3.

Is it something that myself or someone else could work on a formal proposal for?

Yes, absolutely. This is a case where I think it’s useful to design what we want, even if we cannot fit the implementation into the Swift 3 schedule. It’s also a case where the compiler has a lot of the pieces already implemented (with some runtime bits landing soon), so the implementation should not be *that* hard and will likely not require architectural changes.

Interesting. I was under the impression the core team was taking on the generics features. I am also very interested in helping to accelerate the process if that is possible (whether that means Swift 3 or not).

Are you thinking specifically about unbound existentials like in your Equatable example or also partly / fully bound existentials such as SequenceType<Generator.Element == Int>?

···

On Jan 4, 2016, at 12:21 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 3, 2016, at 4:19 PM, David Waite <david@alkaline-solutions.com <mailto:david@alkaline-solutions.com>> wrote:

  - Doug

-DW

On Jan 3, 2016, at 4:17 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jan 3, 2016, at 6:48 AM, Антон Жилин via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Introduction of interfaces will clean up the current blend of static and dynamic protocols, and solve at least three popular issues.
Please see:
https://github.com/Anton3/swift-evolution/blob/master/proposals/0000-introducing-interfaces.md

I am *completely* against this proposal.

Fundamentally, you're trying to address the limitation that protocols with Self or associated type requirements can't be existential. But it's just a limitation that isn't (conceptually) that hard to fix: the primary operation you need to work with an existing of such a protocol is to "open" a value of existential type, giving a name to the dynamic type it stores. Let's invent one:

  func eq(x: Equatable, y: Equatable) -> Bool {
    // give the name T to the dynamic type stored in xT
    let xT = open x as T
    // is y also storing a T?
    guard let yT = y as? T else { return false }
    // check whether the Ts are equal
    return xT == yT
  }

Ignore the syntax: semantically, we've gone from a "dynamic" existential thing back to something more "static", just by giving a name to the type. Swift generics aren't really even static in any sense: what the do is give names to the types of values so one can establish relationships among different values. "open..as" would do that for existentials.

Note that ether Swift compilers AST and SIL both have "open existential" operations that do this internally. They have no spelling in Swift code, but they are useful to describe operations on existentials. At present, they cannot be formed when the existential involves a protocol with Self or associated type requirements, but that's a limitation that isn't hard to address.

As for your concerns about knowing when one can dynamically override and when one cannot... There are issues here that need to be addressed. They aren't significant enough to warrant such a drastic change, and may not even require language changes at all.

  - Doug

_______________________________________________
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


(Drew Crawford) #12

Existentials for protocols with Self and / or associated type requirements would require bindings for Self and / or the associated type(s). At least when you use a member that contains Self and / or an associated type in its signature. So the previous example will always fail to compile.

Not true. Joe Groff:

···

This seems like it would be addressed just by allowing Factory to be used as a dynamic type, with its Product type generalized to Any. We'll be set up to support that with some runtime work to store associated types in protocol witness tables (which is also necessary to fix cyclic conformances, one of our Swift 3 goals).

Yeah, when generalizing a protocol type, we ought to be able to either generalize the associated types to their upper bounds, for use cases like yours, or constrain them to specific types, for the AnyGenerator<T> kind of case.


(Douglas Gregor) #13

This would be wonderful - is it something that could happen in the Swift 3 timeframe?

I hesitate to say “yes” here. I think it fits with the goals of Swift 3, but my main concern is that there isn’t enough engineering bandwidth to implement it for Swift 3.

Is it something that myself or someone else could work on a formal proposal for?

Yes, absolutely. This is a case where I think it’s useful to design what we want, even if we cannot fit the implementation into the Swift 3 schedule. It’s also a case where the compiler has a lot of the pieces already implemented (with some runtime bits landing soon), so the implementation should not be *that* hard and will likely not require architectural changes.

Interesting. I was under the impression the core team was taking on the generics features.

We are, and lots of them. I doubt we can handle another.

I am also very interested in helping to accelerate the process if that is possible (whether that means Swift 3 or not).

Are you thinking specifically about unbound existentials like in your Equatable example or also partly / fully bound existentials such as SequenceType<Generator.Element == Int>?

I was thinking mostly about the former. However, the latter is also a highly-requested feature [*] that complements this one, and I think it’s reasonable to discuss both together.

  - Doug

[*] And is often the underlying reason why developers ask for parameterized protocols.

···

On Jan 4, 2016, at 10:30 AM, Matthew Johnson <matthew@anandabits.com> wrote:

On Jan 4, 2016, at 12:21 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jan 3, 2016, at 4:19 PM, David Waite <david@alkaline-solutions.com <mailto:david@alkaline-solutions.com>> wrote:

  - Doug

-DW

On Jan 3, 2016, at 4:17 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jan 3, 2016, at 6:48 AM, Антон Жилин via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Introduction of interfaces will clean up the current blend of static and dynamic protocols, and solve at least three popular issues.
Please see:
https://github.com/Anton3/swift-evolution/blob/master/proposals/0000-introducing-interfaces.md

I am *completely* against this proposal.

Fundamentally, you're trying to address the limitation that protocols with Self or associated type requirements can't be existential. But it's just a limitation that isn't (conceptually) that hard to fix: the primary operation you need to work with an existing of such a protocol is to "open" a value of existential type, giving a name to the dynamic type it stores. Let's invent one:

  func eq(x: Equatable, y: Equatable) -> Bool {
    // give the name T to the dynamic type stored in xT
    let xT = open x as T
    // is y also storing a T?
    guard let yT = y as? T else { return false }
    // check whether the Ts are equal
    return xT == yT
  }

Ignore the syntax: semantically, we've gone from a "dynamic" existential thing back to something more "static", just by giving a name to the type. Swift generics aren't really even static in any sense: what the do is give names to the types of values so one can establish relationships among different values. "open..as" would do that for existentials.

Note that ether Swift compilers AST and SIL both have "open existential" operations that do this internally. They have no spelling in Swift code, but they are useful to describe operations on existentials. At present, they cannot be formed when the existential involves a protocol with Self or associated type requirements, but that's a limitation that isn't hard to address.

As for your concerns about knowing when one can dynamically override and when one cannot... There are issues here that need to be addressed. They aren't significant enough to warrant such a drastic change, and may not even require language changes at all.

  - Doug

_______________________________________________
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


(Matthew Johnson) #14

This would be wonderful - is it something that could happen in the Swift 3 timeframe?

I hesitate to say “yes” here. I think it fits with the goals of Swift 3, but my main concern is that there isn’t enough engineering bandwidth to implement it for Swift 3.

Is it something that myself or someone else could work on a formal proposal for?

Yes, absolutely. This is a case where I think it’s useful to design what we want, even if we cannot fit the implementation into the Swift 3 schedule. It’s also a case where the compiler has a lot of the pieces already implemented (with some runtime bits landing soon), so the implementation should not be *that* hard and will likely not require architectural changes.

Interesting. I was under the impression the core team was taking on the generics features.

We are, and lots of them. I doubt we can handle another.

I am also very interested in helping to accelerate the process if that is possible (whether that means Swift 3 or not).

Are you thinking specifically about unbound existentials like in your Equatable example or also partly / fully bound existentials such as SequenceType<Generator.Element == Int>?

I was thinking mostly about the former. However, the latter is also a highly-requested feature [*] that complements this one, and I think it’s reasonable to discuss both together.

  - Doug

[*] And is often the underlying reason why developers ask for parameterized protocols.

Agree. The other primary motivation I know of for that request is something like ConvertibleTo<T> where you multiple conformances would be possible.

I am familiar with the reasons why Swift is avoiding that path. :slight_smile:

···

On Jan 4, 2016, at 12:40 PM, Douglas Gregor <dgregor@apple.com> wrote:

On Jan 4, 2016, at 10:30 AM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

On Jan 4, 2016, at 12:21 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jan 3, 2016, at 4:19 PM, David Waite <david@alkaline-solutions.com <mailto:david@alkaline-solutions.com>> wrote:

  - Doug

-DW

On Jan 3, 2016, at 4:17 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jan 3, 2016, at 6:48 AM, Антон Жилин via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Introduction of interfaces will clean up the current blend of static and dynamic protocols, and solve at least three popular issues.
Please see:
https://github.com/Anton3/swift-evolution/blob/master/proposals/0000-introducing-interfaces.md

I am *completely* against this proposal.

Fundamentally, you're trying to address the limitation that protocols with Self or associated type requirements can't be existential. But it's just a limitation that isn't (conceptually) that hard to fix: the primary operation you need to work with an existing of such a protocol is to "open" a value of existential type, giving a name to the dynamic type it stores. Let's invent one:

  func eq(x: Equatable, y: Equatable) -> Bool {
    // give the name T to the dynamic type stored in xT
    let xT = open x as T
    // is y also storing a T?
    guard let yT = y as? T else { return false }
    // check whether the Ts are equal
    return xT == yT
  }

Ignore the syntax: semantically, we've gone from a "dynamic" existential thing back to something more "static", just by giving a name to the type. Swift generics aren't really even static in any sense: what the do is give names to the types of values so one can establish relationships among different values. "open..as" would do that for existentials.

Note that ether Swift compilers AST and SIL both have "open existential" operations that do this internally. They have no spelling in Swift code, but they are useful to describe operations on existentials. At present, they cannot be formed when the existential involves a protocol with Self or associated type requirements, but that's a limitation that isn't hard to address.

As for your concerns about knowing when one can dynamically override and when one cannot... There are issues here that need to be addressed. They aren't significant enough to warrant such a drastic change, and may not even require language changes at all.

  - Doug

_______________________________________________
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


(Anton Zhilin) #15

Cleared up that interfaces can be used in static dispatch as well. Added
other possible keyword variants instead of protocol/interface (there may
still be more). Added some lines about interoperation with existentials
proposal.
I agree that current proposal is in opposition of it, and that existentials
proposal can be cleaner if properly implemented. Whether the two proposals
are compatible, will be more clear once the syntax for existential types is
established.

Proposal page:
https://github.com/Anton3/swift-evolution/blob/master/proposals/0000-introducing-interfaces.md


(David Waite) #16

Resurrecting this conversation, I’ve been working on a proposal to (I believe) cover all these points. I’ve decided it is probably better to resurrect this conversation first in order to start having discussion about the features in general, rather than my specific proposal.

Specifically I am seeking to define:
1. The ability for protocols with Self or associated type constraints to be used other than as generic constraints on concrete types (i.e. as existential types)
2. The ability to use said protocols with none, some, or all of the associated types being constrained/bound.
3. Rules on what functionality (methods, properties) are exposed when working with a protocol (in various states of constraint) rather than a concrete type.
4. The ability to dynamically capture and use a concrete type for the purpose of satisfying Self constraints. This one is the least specified at the moment, but seems the best way to deal with Self constraints.

For the first three, I’ve tried to keep the behavior as close to as if I had instead defined a new protocol without self or associated types based on the constraints given, then had every concrete type in the system meeting the old protocol and the constraints be extended to implement the new one. (This model ignores that there are cases you cannot declare extensions like this today, such as extending a protocol to support another protocol, or extending either a concrete type or protocol to support a new protocol conditionally.)

These new protocols include exposing methods which are invariant based on the constraints given, or which have covariant return types (e.g. functions returning Self would indicate they return instances of this protocol).

The rule complexity hopefully will be sophisticated enough to expose (for example) an unbound SequenceType filter method with the approx. signature: “func filter(includedElements:(Any) throws -> Bool ) rethrows -> [Any]” based on existing function/array behavior.

Non-bikeshedded syntax currently is something in the manner of:

let x:SequenceType = [1,2,3] // no constraints specified whatsoever
let y:protocol<SequenceType where Generator.Element == String> = [“foo”, “bar”] // partially constrained

One interesting side-effect to note is that SequenceType could be redefined to only have “Element” as an associated type. Instead of Generator or SubSequence being associated types, methods could return partially constrained GenericType or SequenceType from the appropriate methods. This would be one way of eliminating issues today with recursive use of associated types (as well as SubSequence over-constraining the output of various algorithms to a single concrete type)

For the “opening” of an existential type to find the concrete type it stores dynamically, I’m currently using a different syntax just because the “open x as T” originally given makes ‘open’ a keyword’ and makes it unclear where ’T’ came from - I’m instead overloading the typealias keyword when used within an expression context:

typealias T = x.dynamicType
let xT = x as! T

My next step is to become more familiar with the bounds of what can be done with this today by the AST/SIL. In particular, using “typealias” as above may imply capabilities which are simply more dynamic than is feasible/appropriate to support.

-DW

···

On Jan 4, 2016, at 11:40 AM, Douglas Gregor <dgregor@apple.com> wrote:

On Jan 4, 2016, at 10:30 AM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:
Interesting. I was under the impression the core team was taking on the generics features.

We are, and lots of them. I doubt we can handle another.

I am also very interested in helping to accelerate the process if that is possible (whether that means Swift 3 or not).

Are you thinking specifically about unbound existentials like in your Equatable example or also partly / fully bound existentials such as SequenceType<Generator.Element == Int>?

I was thinking mostly about the former. However, the latter is also a highly-requested feature [*] that complements this one, and I think it’s reasonable to discuss both together.

  - Doug

[*] And is often the underlying reason why developers ask for parameterized protocols.


(Matthew Johnson) #17

Existentials for protocols with Self and / or associated type requirements would require bindings for Self and / or the associated type(s). At least when you use a member that contains Self and / or an associated type in its signature. So the previous example will always fail to compile.

Not true. Joe Groff:

Can you point me to the source? I would like more context around these comments.

···

On Jan 3, 2016, at 9:08 PM, Drew Crawford <drew@sealedabstract.com> wrote:

This seems like it would be addressed just by allowing Factory to be used as a dynamic type, with its Product type generalized to Any. We'll be set up to support that with some runtime work to store associated types in protocol witness tables (which is also necessary to fix cyclic conformances, one of our Swift 3 goals).

Yeah, when generalizing a protocol type, we ought to be able to either generalize the associated types to their upper bounds, for use cases like yours, or constrain them to specific types, for the AnyGenerator<T> kind of case.


(David Waite) #18

No feedback at all?

-David Waite

···

On Jan 13, 2016, at 3:50 PM, David Waite via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 4, 2016, at 11:40 AM, Douglas Gregor <dgregor@apple.com <mailto:dgregor@apple.com>> wrote:

On Jan 4, 2016, at 10:30 AM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:
Interesting. I was under the impression the core team was taking on the generics features.

We are, and lots of them. I doubt we can handle another.

I am also very interested in helping to accelerate the process if that is possible (whether that means Swift 3 or not).

Are you thinking specifically about unbound existentials like in your Equatable example or also partly / fully bound existentials such as SequenceType<Generator.Element == Int>?

I was thinking mostly about the former. However, the latter is also a highly-requested feature [*] that complements this one, and I think it’s reasonable to discuss both together.

  - Doug

[*] And is often the underlying reason why developers ask for parameterized protocols.

Resurrecting this conversation, I’ve been working on a proposal to (I believe) cover all these points. I’ve decided it is probably better to resurrect this conversation first in order to start having discussion about the features in general, rather than my specific proposal.

Specifically I am seeking to define:
1. The ability for protocols with Self or associated type constraints to be used other than as generic constraints on concrete types (i.e. as existential types)
2. The ability to use said protocols with none, some, or all of the associated types being constrained/bound.
3. Rules on what functionality (methods, properties) are exposed when working with a protocol (in various states of constraint) rather than a concrete type.
4. The ability to dynamically capture and use a concrete type for the purpose of satisfying Self constraints. This one is the least specified at the moment, but seems the best way to deal with Self constraints.

For the first three, I’ve tried to keep the behavior as close to as if I had instead defined a new protocol without self or associated types based on the constraints given, then had every concrete type in the system meeting the old protocol and the constraints be extended to implement the new one. (This model ignores that there are cases you cannot declare extensions like this today, such as extending a protocol to support another protocol, or extending either a concrete type or protocol to support a new protocol conditionally.)

These new protocols include exposing methods which are invariant based on the constraints given, or which have covariant return types (e.g. functions returning Self would indicate they return instances of this protocol).

The rule complexity hopefully will be sophisticated enough to expose (for example) an unbound SequenceType filter method with the approx. signature: “func filter(includedElements:(Any) throws -> Bool ) rethrows -> [Any]” based on existing function/array behavior.

Non-bikeshedded syntax currently is something in the manner of:

let x:SequenceType = [1,2,3] // no constraints specified whatsoever
let y:protocol<SequenceType where Generator.Element == String> = [“foo”, “bar”] // partially constrained

One interesting side-effect to note is that SequenceType could be redefined to only have “Element” as an associated type. Instead of Generator or SubSequence being associated types, methods could return partially constrained GenericType or SequenceType from the appropriate methods. This would be one way of eliminating issues today with recursive use of associated types (as well as SubSequence over-constraining the output of various algorithms to a single concrete type)

For the “opening” of an existential type to find the concrete type it stores dynamically, I’m currently using a different syntax just because the “open x as T” originally given makes ‘open’ a keyword’ and makes it unclear where ’T’ came from - I’m instead overloading the typealias keyword when used within an expression context:

typealias T = x.dynamicType
let xT = x as! T

My next step is to become more familiar with the bounds of what can be done with this today by the AST/SIL. In particular, using “typealias” as above may imply capabilities which are simply more dynamic than is feasible/appropriate to support.

-DW

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


(Douglas Gregor) #19

Interesting. I was under the impression the core team was taking on the generics features.

We are, and lots of them. I doubt we can handle another.

I am also very interested in helping to accelerate the process if that is possible (whether that means Swift 3 or not).

Are you thinking specifically about unbound existentials like in your Equatable example or also partly / fully bound existentials such as SequenceType<Generator.Element == Int>?

I was thinking mostly about the former. However, the latter is also a highly-requested feature [*] that complements this one, and I think it’s reasonable to discuss both together.

  - Doug

[*] And is often the underlying reason why developers ask for parameterized protocols.

Resurrecting this conversation, I’ve been working on a proposal to (I believe) cover all these points. I’ve decided it is probably better to resurrect this conversation first in order to start having discussion about the features in general, rather than my specific proposal.

Specifically I am seeking to define:
1. The ability for protocols with Self or associated type constraints to be used other than as generic constraints on concrete types (i.e. as existential types)
2. The ability to use said protocols with none, some, or all of the associated types being constrained/bound.
3. Rules on what functionality (methods, properties) are exposed when working with a protocol (in various states of constraint) rather than a concrete type.
4. The ability to dynamically capture and use a concrete type for the purpose of satisfying Self constraints. This one is the least specified at the moment, but seems the best way to deal with Self constraints.

Okay.

For the first three, I’ve tried to keep the behavior as close to as if I had instead defined a new protocol without self or associated types based on the constraints given, then had every concrete type in the system meeting the old protocol and the constraints be extended to implement the new one. (This model ignores that there are cases you cannot declare extensions like this today, such as extending a protocol to support another protocol, or extending either a concrete type or protocol to support a new protocol conditionally.)

These new protocols include exposing methods which are invariant based on the constraints given, or which have covariant return types (e.g. functions returning Self would indicate they return instances of this protocol).

The rule complexity hopefully will be sophisticated enough to expose (for example) an unbound SequenceType filter method with the approx. signature: “func filter(includedElements:(Any) throws -> Bool ) rethrows -> [Any]” based on existing function/array behavior.

Non-bikeshedded syntax currently is something in the manner of:

let x:SequenceType = [1,2,3] // no constraints specified whatsoever
let y:protocol<SequenceType where Generator.Element == String> = [“foo”, “bar”] // partially constrained

Not wanting to start throwing paint, but "Generator.Element" could be ambiguous with a Generator in the lexical scope. You'll probably want some way to differentiate it (eg, a leading dot). Otherwise, this is the syntactic direction that I think makes the most sense.

One interesting side-effect to note is that SequenceType could be redefined to only have “Element” as an associated type. Instead of Generator or SubSequence being associated types, methods could return partially constrained GenericType or SequenceType from the appropriate methods. This would be one way of eliminating issues today with recursive use of associated types (as well as SubSequence over-constraining the output of various algorithms to a single concrete type)

Assuming nobody cares about the identity of the Generator type, which is probably a safe assumption. Note that one could implement this design today by using a function taking no arguments and returning an Element? in lieu of "Generator".

For the “opening” of an existential type to find the concrete type it stores dynamically, I’m currently using a different syntax just because the “open x as T” originally given makes ‘open’ a keyword’ and makes it unclear where ’T’ came from

Yes, the issue of "which name did I introduce?" is tricky here.

- I’m instead overloading the typealias keyword when used within an expression context:

typealias T = x.dynamicType
let xT = x as! T

x will have to be immutable for this to make sense. That's why my ugly "open" expression extracts a new value and gives it a fresh type in one lexically-scoped block. Both the type and the value end up being scoped. Otherwise, one might reassign "x" with a different dynamic type... Then what does T mean?

My next step is to become more familiar with the bounds of what can be done with this today by the AST/SIL. In particular, using “typealias” as above may imply capabilities which are simply more dynamic than is feasible/appropriate to support.

I suggest you also look at what can be done with an existential value that hasn't been opened explicitly. Can I call "generate" on a SequenceType value, and what do I get back?

  - Doug

···

Sent from my iPhone

On Jan 13, 2016, at 2:50 PM, David Waite <david@alkaline-solutions.com> wrote:

On Jan 4, 2016, at 11:40 AM, Douglas Gregor <dgregor@apple.com> wrote:
On Jan 4, 2016, at 10:30 AM, Matthew Johnson <matthew@anandabits.com> wrote:


(Drew Crawford) #20

Sure, here's the start of the thread: https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/001856.html

···

On Jan 3, 2016, at 9:10 PM, Matthew Johnson <matthew@anandabits.com> wrote:

On Jan 3, 2016, at 9:08 PM, Drew Crawford <drew@sealedabstract.com> wrote:

Existentials for protocols with Self and / or associated type requirements would require bindings for Self and / or the associated type(s). At least when you use a member that contains Self and / or an associated type in its signature. So the previous example will always fail to compile.

Not true. Joe Groff:

Can you point me to the source? I would like more context around these comments.

This seems like it would be addressed just by allowing Factory to be used as a dynamic type, with its Product type generalized to Any. We'll be set up to support that with some runtime work to store associated types in protocol witness tables (which is also necessary to fix cyclic conformances, one of our Swift 3 goals).

Yeah, when generalizing a protocol type, we ought to be able to either generalize the associated types to their upper bounds, for use cases like yours, or constrain them to specific types, for the AnyGenerator<T> kind of case.