[Pitch] Remove type inference for associated types

I didn't design it, but here's how I think about it: The associated type requirement merely states that there must be a type with this name meeting these criteria. `typealias` is one way to satisfy that requirement, but you can also just define a nested type with that name:

  struct MyCollection {
    struct Index: Comparable { … }
  }

Should you replace `struct` with `associatedtype`? No? Then why would you replace `typealias` with `associatedtype`?

···

On Jun 29, 2016, at 6:55 AM, Brandon Knope via swift-evolution <swift-evolution@swift.org> wrote:

What's the rationale for having associatedtype in protocols and typealias in the conforming types?

--
Brent Royal-Gordon
Architechies

Thanks for your response, Dave.

There is a bit of a dilemma here: wait until the generics and type system
features have stabilized at the risk of making major source-breaking
changes after 3.0, or make changes now without clarity about the future of
the generics system.

Given that this topic showed up both in Chris's list of open design topics
and in the generics manifesto, I assume that someone on the core team
wanted a discussion about it before Swift 3 closes. I would be interested
in knowing if that's true.

Best,
Austin

···

On Mon, Jun 27, 2016 at 12:56 PM, Dave Abrahams via swift-evolution < swift-evolution@swift.org> wrote:

on Sat Jun 25 2016, Austin Zheng <swift-evolution@swift.org> wrote:

>> On Jun 25, 2016, at 6:23 AM, Matthew Johnson <matthew@anandabits.com> > wrote:
>>
>> Hi Austin,
>>
>> I’m sorry to say, but this proposal makes me really sad. I consider
>> associated type inference one of the more elegant aspects of Swift.
>> It would be very unfortunate to lose it.
>
> There are lots of "elegant" things that Swift could do, but has chosen
> not to do for pragmatic reasons (e.g. generalized implicit
> conversions, type inference that crosses statement boundaries). Given
> how terrible the development experience can be right now in the worst
> case, I would happily trade off some measure of convenience for better
> tooling.

Well, the type checker's inference engine has *always* been kinda
unreliable, and the experience is made much worse by the lack of
recursive protocol requirements and the inability to express other
constraints that would better guide inference, and by the “underscored
protocols” such as _Indexable that are required to work around those
limitations. IMO it's premature to remove this feature before the
inference engine is made sane, the generics features are added, and the
library is correspondingly cleaned up, because we don't really know what
the user experience would be.

Finally, I am very concerned that there are protocols such as Collection,
with many inferrable associated types, and that conforming to these
protocols could become *much* uglier.

--
Dave

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

Hi Austin,

I’m sorry to say, but this proposal makes me really sad. I consider
associated type inference one of the more elegant aspects of Swift.
It would be very unfortunate to lose it.

There are lots of "elegant" things that Swift could do, but has chosen
not to do for pragmatic reasons (e.g. generalized implicit
conversions, type inference that crosses statement boundaries). Given
how terrible the development experience can be right now in the worst
case, I would happily trade off some measure of convenience for better
tooling.

Well, the type checker's inference engine has *always* been kinda
unreliable,

Dave is dramatically understating the pain that this inference has caused. Because this is the only place we do global type inference, it’s put tremendous pressure on the type checker that caused a huge number of bugs, crashes, and outright incomprehensible behavior. I reimplemented the inference of associated type witnesses in April of 2015 (Reimplement inference of type witnesses with a separate non-recursive… · apple/swift@126e404 · GitHub, for reference), when the existing implementation unbearable. It got *far* better, but it’s still not global *enough* to actually be predictable, and the legacy of this mis-feature manifests in a number of weird ways (e.g., typealiases in protocol extensions cannot be used to satisfy associated type requirements, weird rules for when a defaulted associated type gets used).

and the experience is made much worse by the lack of
recursive protocol requirements and the inability to express other
constraints that would better guide inference, and by the “underscored
protocols” such as _Indexable that are required to work around those
limitations. IMO it's premature to remove this feature before the
inference engine is made sane, the generics features are added, and the
library is correspondingly cleaned up, because we don't really know what
the user experience would be.

Well, there’s a chicken-and-egg problem. The complexity of this inference is getting in the way of other improvements. For example, inference of associated types for conditional conformances requires that associated type witness deduction consider additional requirements, which is a complexity we would entirely avoid

Finally, I am very concerned that there are protocols such as Collection,
with many inferrable associated types, and that conforming to these
protocols could become *much* uglier.

That’s the general concern I have as well: how much boilerplate does this add? In many cases, we get some of the associated type witnesses for Collection types for free, and I don’t know to what extent we can emulate that with defaulted associated type requirements and typealiases in protocol extensions.

That said, I’ll take some minor regressions in this area for the massive simplification that this proposal brings.

  - Doug

···

On Jun 27, 2016, at 12:56 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:
on Sat Jun 25 2016, Austin Zheng <swift-evolution@swift.org> wrote:

On Jun 25, 2016, at 6:23 AM, Matthew Johnson <matthew@anandabits.com> wrote:

Inline

Sent from my iPad

I actually think that the delineation between `associatedtype` and
`typealias` should make this legal, and will change the proposal as such.
It should be legal to bind an associated type to a type alias, and it
should be possible to define a type alias that shadows (but does not
conflict with) an associated type definition. This would fix the issue with
retroactive modeling.

IIUC you're saying a type is allowed to have an `associatedtype` and
`typealias` (or nested type) both bound to the same name as long as they
resolve to the same type. Is that correct? That would at least preserve
current expressiveness.

Yes, that is exactly correct :).

I actually have an alternative (see the last sub-entry in the alternative
section) that would relax even that restriction. This would actually make
the language slightly more expressive, since you would _theoretically_ be
able to get around the typealias or nested type aliasing issues that exist
today. I argued a bit against it but it's there in case the core team
disagrees.

// Module A
public struct S {
    public typealias Foo = Int
}

// Module B
public protocol P {
    associatedtype Foo
}

// Module C
import A
import B

// compiler error: `S` does not meet the `Foo` associatedtype requirement
extension S : P {
    // compiler error: cannot define associatedtype `Foo` for `S` which
already declares typealias `Foo`
    associatedtype Foo = String
}

I cannot support any proposal that breaks retroactive modeling in this way.

Addendum aside, retroactive modeling is already suboptimal or broken in
multiple ways today - try conforming a protocol with associated type
'Element' to a different protocol whose 'Element' means something
completely different.

Did you mean conforming a type to two protocols with an 'Element'
associatedtype?

I consider that issue to be in the realm of multiple conformances rather
than retroactive modeling. I can still

Yeah, I completely mangled that sentence.

I think it does fall into the realm of retroactive modeling, since an
existing type may be prevented from being retroactively conformed to a new
protocol by an existing conformance that it has.

Thank you for adding the clarifications. I feel a little better knowing
we wouldn't lose expressive power, but still prefer the directed inference
suggested by Dmitri.

And thank you for your honest feedback!

···

On Mon, Jun 27, 2016 at 6:47 AM, Matthew Johnson <matthew@anandabits.com> wrote:

On Jun 25, 2016, at 12:41 PM, Austin Zheng <austinzheng@gmail.com> wrote:

This was one of the rationales for the original design, which used associatedtype instead of typealias. There is a link to it at the bottom of the current proposal.

···

Sent from my iPhone

On Jun 29, 2016, at 8:16 AM, Brandon Knope via swift-evolution <swift-evolution@swift.org> wrote:

This is true! Swift is suppose to be a safe language that can prevent these kind of pitfalls.

But I feel there was a rationale for having the way it is...I just don't know it

Brandon

On Jun 29, 2016, at 10:21 AM, Sean Heber <sean@fifthace.com> wrote:

Another issue here (perhaps) is, what if you misspelled the associated type when you attempted to typealias it manually? Would it not just make a new typealias with your misspelled name and then, potentially, you’d get an error or would something end up working but in unexpected ways? Would the typo be easy to identify if you had a lot of typealiases or associatedtypes or typos?

  protocol P {
    associatedtype Index = Int
  }

  struct X : P {
    typealias index = String // whoops - no capital I - how long does this bug take to find? :P
  }

There will always be bugs, of course. Maybe this isn’t a significant concern?

l8r
Sean

On Jun 29, 2016, at 8:55 AM, Brandon Knope via swift-evolution <swift-evolution@swift.org> wrote:

What's the rationale for having associatedtype in protocols and typealias in the conforming types?

This has actually been a point of confusion for me as it seems inconsistent

Brandon

Sent from my iPad

On Jun 29, 2016, at 1:33 AM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

On Jun 24, 2016, at 10:50 PM, Austin Zheng via swift-evolution <swift-evolution@swift.org> wrote:

Hello all,

Per Chris Lattner's list of open Swift 3 design topics (http://article.gmane.org/gmane.comp.lang.swift.evolution/21369\), I've put together a proposal for removing type inference for associated types.

It can be found here: https://github.com/austinzheng/swift-evolution/blob/az-assoctypeinf/proposals/XXXX-remove-assoctype-inference.md

Thoughts, criticism, and feedback welcome. There are at least two slightly different designs in the proposal, and I'm sure people will have ideas for even more.

Thanks for working on this. I have a couple of comments.

I don’t think we should be adding the ability to write ‘associatedtype’ declarations in classes/structs/enums. We already have the ability to explicitly state the associated type witness by declaring a typealias, struct, enum, or class with the appropriate name. Indeed, I feel like a lot of complexity of the proposal is linked to adding ‘associatedtype’ declarations into the language, and I’d rather this proposal stay narrow.

I think it’s important for this proposal to show the other ways in which one can get associated type witnesses without writing them explicitly in the conforming type, even once inference goes away. For example, we have associated type defaults, e.g.,

  protocol P {
    associatedtype Associated = Int
  }

  struct X : P {
    // Associated becomes Int if not otherwise specified
  }

and with typealiases in protocol extensions becoming real and useful, one could also use protocol extensions:

  protocol P2 {
    associatedtype Index
  }

  extension P2 {
    typealias Index = Int
  }

which, of course, implies that one can use various tricks with constrained protocol extensions and such. There isn’t any proposed change here, but it illustrates that Swift programmers aren’t without recourse if type inference for associated types go away.

One concern with applying the above tricks is that existing code can change meaning when inference goes away. For example, let’s think about the “Iterator” type of a Sequence. It already uses default associated type witnesses (not associated type witness inference!) to give a default of IndexingIterator<Self>, e.g.,

  protocol Sequence {
    associatedtype Iterator: IteratorType
    func makeIterator() -> Iterator
  }

  protocol Collection : Sequence {
    associatedtype Iterator = IndexingIterator<Self>
    func makeIterator() -> Iterator // redeclaration helps inference
  }

When a type that conforms to Collection doesn’t provide makeIterator, it gets a default one via:

  extension Collection where Iterator == IndexingIterator<Self> {
    public func makeIterator() -> IndexingIterator<Self> { … }
  }

That will still work (yay). However, simply removing associated type inference means that a collection type that *does* provide makeIterator()—but not, directly, Iterator—would change behavior:

  struct IntCollection : Collection {
    typealias Element = Int
    func makeIterator() -> IntCollectionIterator { … }
  }

With associated type inference, we infer Iterator = IntCollectionIterator and select IntCollection.makeIterator() to satisfy the makeIterator() requirement.

Without associated type inference, we use the default Iterator = IndexingIterator<Self> and select the makeIterator() from the protocol extension (because IntCollection.makeIterator() now returns the wrong type), which turns an error of omission into an unpleasant surprise. We might need something like near-miss checking for defaulted protocol requirements (which we discussed in the thread at http://thread.gmane.org/gmane.comp.lang.swift.devel/1799\) to help find those surprises. They already exist today, of course, but removing associated type inference would make them worse.

Finally, one of the chief concerns is that we won’t be able to provide a nice experience when conforming to the standard library’s collection protocols. I would *love* to see some more thought to into how we can use the above tools to handle it, although I suspect the only way to do that is to implement some part of this proposal experimentally and see what it takes to get the standard library and it’s tests working again. How far can the tools above go toward reducing the need to specify various associated type witnesses in conforming types? What are the surprises?

  - 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

The detailed design section of

  https://github.com/apple/swift-evolution/blob/master/proposals/0108-remove-assoctype-inference.md

Now talks about this. It's not a new problem, and I'm firstly confident that the near-miss checking approach will address the issues.

···

Sent from my iPhone

On Jun 29, 2016, at 8:16 AM, Brandon Knope <bknope@me.com> wrote:

This is true! Swift is suppose to be a safe language that can prevent these kind of pitfalls.

But I feel there was a rationale for having the way it is...I just don't know it

Brandon

On Jun 29, 2016, at 10:21 AM, Sean Heber <sean@fifthace.com> wrote:

Another issue here (perhaps) is, what if you misspelled the associated type when you attempted to typealias it manually? Would it not just make a new typealias with your misspelled name and then, potentially, you’d get an error or would something end up working but in unexpected ways? Would the typo be easy to identify if you had a lot of typealiases or associatedtypes or typos?

  protocol P {
    associatedtype Index = Int
  }

  struct X : P {
    typealias index = String // whoops - no capital I - how long does this bug take to find? :P
  }

There will always be bugs, of course. Maybe this isn’t a significant concern?

l8r
Sean

On Jun 29, 2016, at 8:55 AM, Brandon Knope via swift-evolution <swift-evolution@swift.org> wrote:

What's the rationale for having associatedtype in protocols and typealias in the conforming types?

This has actually been a point of confusion for me as it seems inconsistent

Brandon

Sent from my iPad

On Jun 29, 2016, at 1:33 AM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

On Jun 24, 2016, at 10:50 PM, Austin Zheng via swift-evolution <swift-evolution@swift.org> wrote:

Hello all,

Per Chris Lattner's list of open Swift 3 design topics (http://article.gmane.org/gmane.comp.lang.swift.evolution/21369\), I've put together a proposal for removing type inference for associated types.

It can be found here: https://github.com/austinzheng/swift-evolution/blob/az-assoctypeinf/proposals/XXXX-remove-assoctype-inference.md

Thoughts, criticism, and feedback welcome. There are at least two slightly different designs in the proposal, and I'm sure people will have ideas for even more.

Thanks for working on this. I have a couple of comments.

I don’t think we should be adding the ability to write ‘associatedtype’ declarations in classes/structs/enums. We already have the ability to explicitly state the associated type witness by declaring a typealias, struct, enum, or class with the appropriate name. Indeed, I feel like a lot of complexity of the proposal is linked to adding ‘associatedtype’ declarations into the language, and I’d rather this proposal stay narrow.

I think it’s important for this proposal to show the other ways in which one can get associated type witnesses without writing them explicitly in the conforming type, even once inference goes away. For example, we have associated type defaults, e.g.,

  protocol P {
    associatedtype Associated = Int
  }

  struct X : P {
    // Associated becomes Int if not otherwise specified
  }

and with typealiases in protocol extensions becoming real and useful, one could also use protocol extensions:

  protocol P2 {
    associatedtype Index
  }

  extension P2 {
    typealias Index = Int
  }

which, of course, implies that one can use various tricks with constrained protocol extensions and such. There isn’t any proposed change here, but it illustrates that Swift programmers aren’t without recourse if type inference for associated types go away.

One concern with applying the above tricks is that existing code can change meaning when inference goes away. For example, let’s think about the “Iterator” type of a Sequence. It already uses default associated type witnesses (not associated type witness inference!) to give a default of IndexingIterator<Self>, e.g.,

  protocol Sequence {
    associatedtype Iterator: IteratorType
    func makeIterator() -> Iterator
  }

  protocol Collection : Sequence {
    associatedtype Iterator = IndexingIterator<Self>
    func makeIterator() -> Iterator // redeclaration helps inference
  }

When a type that conforms to Collection doesn’t provide makeIterator, it gets a default one via:

  extension Collection where Iterator == IndexingIterator<Self> {
    public func makeIterator() -> IndexingIterator<Self> { … }
  }

That will still work (yay). However, simply removing associated type inference means that a collection type that *does* provide makeIterator()—but not, directly, Iterator—would change behavior:

  struct IntCollection : Collection {
    typealias Element = Int
    func makeIterator() -> IntCollectionIterator { … }
  }

With associated type inference, we infer Iterator = IntCollectionIterator and select IntCollection.makeIterator() to satisfy the makeIterator() requirement.

Without associated type inference, we use the default Iterator = IndexingIterator<Self> and select the makeIterator() from the protocol extension (because IntCollection.makeIterator() now returns the wrong type), which turns an error of omission into an unpleasant surprise. We might need something like near-miss checking for defaulted protocol requirements (which we discussed in the thread at http://thread.gmane.org/gmane.comp.lang.swift.devel/1799\) to help find those surprises. They already exist today, of course, but removing associated type inference would make them worse.

Finally, one of the chief concerns is that we won’t be able to provide a nice experience when conforming to the standard library’s collection protocols. I would *love* to see some more thought to into how we can use the above tools to handle it, although I suspect the only way to do that is to implement some part of this proposal experimentally and see what it takes to get the standard library and it’s tests working again. How far can the tools above go toward reducing the need to specify various associated type witnesses in conforming types? What are the surprises?

  - 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

But surely using two different keywords could seem confusing to many as part of the same system?

Using associatedtype in the declaration and then typealias in the conforming type just seems inconsistent and ripe for confusion. '

I am curious if any advanced Swift users still get tripped up here

Brandon

···

Sent from my iPad

On Jun 30, 2016, at 8:53 AM, Brent Royal-Gordon <brent@architechies.com> wrote:

On Jun 29, 2016, at 6:55 AM, Brandon Knope via swift-evolution <swift-evolution@swift.org> wrote:

What's the rationale for having associatedtype in protocols and typealias in the conforming types?

I didn't design it, but here's how I think about it: The associated type requirement merely states that there must be a type with this name meeting these criteria. `typealias` is one way to satisfy that requirement, but you can also just define a nested type with that name:

   struct MyCollection {
       struct Index: Comparable { … }
   }

Should you replace `struct` with `associatedtype`? No? Then why would you replace `typealias` with `associatedtype`?

--
Brent Royal-Gordon
Architechies

No, but I don't think I'd be opposed to this:
struct MyCollection {
    associatedtype Index = struct _ : Comparable { … } // struct's name is implicitly also "Index"
}

- Dave Sweeris

···

On Jun 30, 2016, at 07:53, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

   struct MyCollection {
       struct Index: Comparable { … }
   }

Should you replace `struct` with `associatedtype`? No? Then why would you replace `typealias` with `associatedtype`?

Thanks for your response, Dave.

There is a bit of a dilemma here: wait until the generics and type system
features have stabilized at the risk of making major source-breaking
changes after 3.0, or make changes now without clarity about the future of
the generics system.

Given that this topic showed up both in Chris's list of open design topics
and in the generics manifesto, I assume that someone on the core team
wanted a discussion about it before Swift 3 closes. I would be interested
in knowing if that's true.

I don't know anything more than you do, I'm afraid.

···

on Mon Jun 27 2016, Austin Zheng <austinzheng-AT-gmail.com> wrote:

Best,
Austin

On Mon, Jun 27, 2016 at 12:56 PM, Dave Abrahams via swift-evolution < > swift-evolution@swift.org> wrote:

on Sat Jun 25 2016, Austin Zheng <swift-evolution@swift.org> wrote:

>> On Jun 25, 2016, at 6:23 AM, Matthew Johnson <matthew@anandabits.com> >> wrote:
>>
>> Hi Austin,
>>
>> I’m sorry to say, but this proposal makes me really sad. I consider
>> associated type inference one of the more elegant aspects of Swift.
>> It would be very unfortunate to lose it.
>
> There are lots of "elegant" things that Swift could do, but has chosen
> not to do for pragmatic reasons (e.g. generalized implicit
> conversions, type inference that crosses statement boundaries). Given
> how terrible the development experience can be right now in the worst
> case, I would happily trade off some measure of convenience for better
> tooling.

Well, the type checker's inference engine has *always* been kinda
unreliable, and the experience is made much worse by the lack of
recursive protocol requirements and the inability to express other
constraints that would better guide inference, and by the “underscored
protocols” such as _Indexable that are required to work around those
limitations. IMO it's premature to remove this feature before the
inference engine is made sane, the generics features are added, and the
library is correspondingly cleaned up, because we don't really know what
the user experience would be.

Finally, I am very concerned that there are protocols such as Collection,
with many inferrable associated types, and that conforming to these
protocols could become *much* uglier.

--
Dave

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

--
Dave

Hi Austin,

I’m sorry to say, but this proposal makes me really sad. I consider
associated type inference one of the more elegant aspects of Swift.
It would be very unfortunate to lose it.

There are lots of "elegant" things that Swift could do, but has chosen
not to do for pragmatic reasons (e.g. generalized implicit
conversions, type inference that crosses statement boundaries). Given
how terrible the development experience can be right now in the worst
case, I would happily trade off some measure of convenience for better
tooling.

Well, the type checker's inference engine has *always* been kinda
unreliable,

Dave is dramatically understating the pain that this inference has caused. Because this is the only place we do global type inference, it’s put tremendous pressure on the type checker that caused a huge number of bugs, crashes, and outright incomprehensible behavior. I reimplemented the inference of associated type witnesses in April of 2015 (Reimplement inference of type witnesses with a separate non-recursive… · apple/swift@126e404 · GitHub, for reference), when the existing implementation unbearable. It got *far* better, but it’s still not global *enough* to actually be predictable, and the legacy of this mis-feature manifests in a number of weird ways (e.g., typealiases in protocol extensions cannot be used to satisfy associated type requirements, weird rules for when a defaulted associated type gets used).

and the experience is made much worse by the lack of
recursive protocol requirements and the inability to express other
constraints that would better guide inference, and by the “underscored
protocols” such as _Indexable that are required to work around those
limitations. IMO it's premature to remove this feature before the
inference engine is made sane, the generics features are added, and the
library is correspondingly cleaned up, because we don't really know what
the user experience would be.

Well, there’s a chicken-and-egg problem. The complexity of this inference is getting in the way of other improvements. For example, inference of associated types for conditional conformances requires that associated type witness deduction consider additional requirements, which is a complexity we would entirely avoid

Finally, I am very concerned that there are protocols such as Collection,
with many inferrable associated types, and that conforming to these
protocols could become *much* uglier.

That’s the general concern I have as well: how much boilerplate does this add? In many cases, we get some of the associated type witnesses for Collection types for free, and I don’t know to what extent we can emulate that with defaulted associated type requirements and typealiases in protocol extensions.

That said, I’ll take some minor regressions in this area for the massive simplification that this proposal brings.

Do you have any comments on Dmitri’s suggested alternative? I would like to see that discussed before any proposals are reviewed. That discussion is likely to influence my opinion quite a bit.

···

On Jun 28, 2016, at 1:25 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

On Jun 27, 2016, at 12:56 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
on Sat Jun 25 2016, Austin Zheng <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jun 25, 2016, at 6:23 AM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

  - Doug

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

Hi Austin,

I’m sorry to say, but this proposal makes me really sad. I consider
associated type inference one of the more elegant aspects of Swift.
It would be very unfortunate to lose it.

There are lots of "elegant" things that Swift could do, but has chosen
not to do for pragmatic reasons (e.g. generalized implicit
conversions, type inference that crosses statement boundaries). Given
how terrible the development experience can be right now in the worst
case, I would happily trade off some measure of convenience for better
tooling.

Well, the type checker's inference engine has *always* been kinda
unreliable,

Dave is dramatically understating the pain that this inference has
caused.

What are you talking about? I did not characterize the magnitude of the
pain in any way whatsoever.

Because this is the only place we do global type inference, it’s put
tremendous pressure on the type checker that caused a huge number of
bugs, crashes, and outright incomprehensible behavior. I reimplemented
the inference of associated type witnesses in April of 2015
(Reimplement inference of type witnesses with a separate non-recursive… · apple/swift@126e404 · GitHub
<https://github.com/apple/swift/commit/126e404fe5bf0be81206f22c83a61f6689d18854&gt;,
for reference), when the existing implementation unbearable. It got
*far* better, but it’s still not global *enough* to actually be
predictable, and the legacy of this mis-feature manifests in a number
of weird ways (e.g., typealiases in protocol extensions cannot be used
to satisfy associated type requirements, weird rules for when a
defaulted associated type gets used).

and the experience is made much worse by the lack of
recursive protocol requirements and the inability to express other
constraints that would better guide inference, and by the “underscored
protocols” such as _Indexable that are required to work around those
limitations. IMO it's premature to remove this feature before the
inference engine is made sane, the generics features are added, and the
library is correspondingly cleaned up, because we don't really know what
the user experience would be.

Well, there’s a chicken-and-egg problem. The complexity of this
inference is getting in the way of other improvements.

I figured that might be the case. If we have to drop that inference in
order to evolve the other improvements in a sane way, I strongly endorse
doing so, at least temporarily :-) But I think we should be prepared to
re-evaluate the situation after the dust settles.

For example, inference of associated types for conditional
conformances requires that associated type witness deduction consider
additional requirements, which is a complexity we would entirely avoid

Finally, I am very concerned that there are protocols such as Collection,
with many inferrable associated types, and that conforming to these
protocols could become *much* uglier.

That’s the general concern I have as well: how much boilerplate does
this add? In many cases, we get some of the associated type witnesses
for Collection types for free, and I don’t know to what extent we can
emulate that with defaulted associated type requirements and
typealiases in protocol extensions.

That said, I’ll take some minor regressions in this area for the
massive simplification that this proposal brings.

It remains to be seen how minor the usability regressions are, of
course.

···

on Tue Jun 28 2016, Douglas Gregor <dgregor-AT-apple.com> wrote:

On Jun 27, 2016, at 12:56 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:
on Sat Jun 25 2016, Austin Zheng <swift-evolution@swift.org> wrote:

On Jun 25, 2016, at 6:23 AM, Matthew Johnson <matthew@anandabits.com> wrote:

--
Dave

Inline

Sent from my iPad

I actually think that the delineation between `associatedtype` and `typealias` should make this legal, and will change the proposal as such. It should be legal to bind an associated type to a type alias, and it should be possible to define a type alias that shadows (but does not conflict with) an associated type definition. This would fix the issue with retroactive modeling.

IIUC you're saying a type is allowed to have an `associatedtype` and `typealias` (or nested type) both bound to the same name as long as they resolve to the same type. Is that correct? That would at least preserve current expressiveness.

Yes, that is exactly correct :).

I actually have an alternative (see the last sub-entry in the alternative section) that would relax even that restriction. This would actually make the language slightly more expressive, since you would _theoretically_ be able to get around the typealias or nested type aliasing issues that exist today. I argued a bit against it but it's there in case the core team disagrees.

// Module A
public struct S {
    public typealias Foo = Int
}

// Module B
public protocol P {
    associatedtype Foo
}

// Module C
import A
import B

// compiler error: `S` does not meet the `Foo` associatedtype requirement
extension S : P {
    // compiler error: cannot define associatedtype `Foo` for `S` which already declares typealias `Foo`
    associatedtype Foo = String
}

I cannot support any proposal that breaks retroactive modeling in this way.

Addendum aside, retroactive modeling is already suboptimal or broken in multiple ways today - try conforming a protocol with associated type 'Element' to a different protocol whose 'Element' means something completely different.

Did you mean conforming a type to two protocols with an 'Element' associatedtype?

I consider that issue to be in the realm of multiple conformances rather than retroactive modeling. I can still

Yeah, I completely mangled that sentence.

I think it does fall into the realm of retroactive modeling, since an existing type may be prevented from being retroactively conformed to a new protocol by an existing conformance that it has.

I suppose you can look at it that way.

Here’s a suggestion for your proposal: if we’re going to go as far as requiring explicit `associatedtype` declarations why not allow disambiguation? If there are two protocols `Foo` and `Bar` both with an `Element` associated type maybe we should be able to write `Foo.Element` and `Bar.Element` if that is necessary to disambiguate. This would also work in cases like the one you mention above when reference your alternative, but without introducing two different bindings for the same name.

It wouldn’t have made sense in the current syntax using `typealias` but if we use a declaration that *only* exists for the purpose of conformance it seems like allowing disambiguation is a rather obvious thing to do (once you think of the idea).

Thank you for adding the clarifications. I feel a little better knowing we wouldn't lose expressive power, but still prefer the directed inference suggested by Dmitri.

And thank you for your honest feedback!

You’re welcome. I’m still hoping we find a way out of this (the idea of writing these out for every conformance is a real bummer), but that hope is fading after reading Doug’s reply to Dmitri. In the end I trust the core team will make the right decision. It seems like the library folks would prefer to avoid dropping inference so I’m sure there will be a healthy debate by folks who are far more expert on this topic than I.

-Matthew

···

On Jun 28, 2016, at 3:24 PM, Austin Zheng <austinzheng@gmail.com> wrote:
On Mon, Jun 27, 2016 at 6:47 AM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:
On Jun 25, 2016, at 12:41 PM, Austin Zheng <austinzheng@gmail.com <mailto:austinzheng@gmail.com>> wrote:

Another point to add to Doug’s great summary: instead of keeping it, it is better in many ways to remove this feature in Swift 3, improve the generics model throughout Swift 4 cycle, and then consider adding inference back when we know more.

The benefits of adding it back will be even more clear in the future, and the implementation cost will also be more knowable as the rest of the generics system is baked out.

-Chris

···

On Jun 28, 2016, at 11:25 AM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

Finally, I am very concerned that there are protocols such as Collection,
with many inferrable associated types, and that conforming to these
protocols could become *much* uglier.

That’s the general concern I have as well: how much boilerplate does this add? In many cases, we get some of the associated type witnesses for Collection types for free, and I don’t know to what extent we can emulate that with defaulted associated type requirements and typealiases in protocol extensions.

That said, I’ll take some minor regressions in this area for the massive simplification that this proposal brings.

I don't see that as confusing. In a conforming type, he compiler is looking for a type with the same name as the associatedtype declaration. As the proposal mentions, typealias is not the only way to provide that type. It's actually logical to typealias to point the compiler to the correct type as well as it is to define a internal type with the same name from the start.

···

On 30 Jun 2016, at 15:22, Brandon Knope via swift-evolution <swift-evolution@swift.org> wrote:

But surely using two different keywords could seem confusing to many as part of the same system?

Using associatedtype in the declaration and then typealias in the conforming type just seems inconsistent and ripe for confusion. '

I am curious if any advanced Swift users still get tripped up here

Brandon

Sent from my iPad

On Jun 30, 2016, at 8:53 AM, Brent Royal-Gordon <brent@architechies.com> wrote:

On Jun 29, 2016, at 6:55 AM, Brandon Knope via swift-evolution <swift-evolution@swift.org> wrote:

What's the rationale for having associatedtype in protocols and typealias in the conforming types?

I didn't design it, but here's how I think about it: The associated type requirement merely states that there must be a type with this name meeting these criteria. `typealias` is one way to satisfy that requirement, but you can also just define a nested type with that name:

  struct MyCollection {
      struct Index: Comparable { … }
  }

Should you replace `struct` with `associatedtype`? No? Then why would you replace `typealias` with `associatedtype`?

--
Brent Royal-Gordon
Architechies

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

I guess we're on the same page then:
http://article.gmane.org/gmane.comp.lang.swift.evolution/22112

···

on Tue Jun 28 2016, Chris Lattner <swift-evolution@swift.org> wrote:

On Jun 28, 2016, at 11:25 AM, Douglas Gregor via swift-evolution >> <swift-evolution@swift.org> wrote:

Finally, I am very concerned that there are protocols such as Collection,

with many inferrable associated types, and that conforming to these
protocols could become *much* uglier.

That’s the general concern I have as well: how much boilerplate does
this add? In many cases, we get some of the associated type
witnesses for Collection types for free, and I don’t know to what
extent we can emulate that with defaulted associated type
requirements and typealiases in protocol extensions.

That said, I’ll take some minor regressions in this area for the
massive simplification that this proposal brings.

Another point to add to Doug’s great summary: instead of keeping it,
it is better in many ways to remove this feature in Swift 3, improve
the generics model throughout Swift 4 cycle, and then consider adding
inference back when we know more.

The benefits of adding it back will be even more clear in the future,
and the implementation cost will also be more knowable as the rest of
the generics system is baked out.

--
Dave

Unfortunately I have a specific use case in which this argument would be very strong.

Basically this:

extension TodoController : ResourceController {}

Would have to become this:

extension TodoController : ResourceController {
    public typealias CreateInput = Todo
    public typealias UpdateInput = Todo

    public typealias ListOutput = Todo
    public typealias CreateOutput = Todo
    public typealias DetailOutput = Todo
    public typealias UpdateOutput = Todo

    public typealias DetailID = String
    public typealias UpdateID = String
    public typealias DestroyID = String
}

I could reduce the amount of associated types but this would reduce the flexibility of the protocol by a huge factor and would make it much less powerful. I’m very torn about this because I do want generics to get better. Specifically I’m looking forward to conditional conformances. But this would be a too high cost imho. I know this is just one example. But maybe there are more examples like this out there. I have to admit this one really got to me. :(

···

On Jun 28, 2016, at 3:34 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

Finally, I am very concerned that there are protocols such as Collection,
with many inferrable associated types, and that conforming to these
protocols could become *much* uglier.

I don't see that as confusing. In a conforming type, he compiler is looking for a type with the same name as the associatedtype declaration. As the proposal mentions, typealias is not the only way to provide that type. It's actually logical to typealias to point the compiler to the correct type as well as it is to define a internal type with the same name from the start.

“associatedtype” used to be “typealias”, because we were trying to make the declaration in the protocol use the same spelling as the common case for conforming types, which turned out to be a bad idea. Hence, SE-0011:

  https://github.com/apple/swift-evolution/blob/master/proposals/0011-replace-typealias-associated.md

  - Doug

···

On Jun 30, 2016, at 9:55 AM, David Hart via swift-evolution <swift-evolution@swift.org> wrote:

On 30 Jun 2016, at 15:22, Brandon Knope via swift-evolution <swift-evolution@swift.org> wrote:

But surely using two different keywords could seem confusing to many as part of the same system?

Using associatedtype in the declaration and then typealias in the conforming type just seems inconsistent and ripe for confusion. '

I am curious if any advanced Swift users still get tripped up here

Brandon

Sent from my iPad

On Jun 30, 2016, at 8:53 AM, Brent Royal-Gordon <brent@architechies.com> wrote:

On Jun 29, 2016, at 6:55 AM, Brandon Knope via swift-evolution <swift-evolution@swift.org> wrote:

What's the rationale for having associatedtype in protocols and typealias in the conforming types?

I didn't design it, but here's how I think about it: The associated type requirement merely states that there must be a type with this name meeting these criteria. `typealias` is one way to satisfy that requirement, but you can also just define a nested type with that name:

struct MyCollection {
     struct Index: Comparable { … }
}

Should you replace `struct` with `associatedtype`? No? Then why would you replace `typealias` with `associatedtype`?

--
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 don't see that as confusing. In a conforming type, he compiler is looking for a type with the same name as the associatedtype declaration. As the proposal mentions, typealias is not the only way to provide that type. It's actually logical to typealias to point the compiler to the correct type as well as it is to define a internal type with the same name from the start.

“associatedtype” used to be “typealias”, because we were trying to make the declaration in the protocol use the same spelling as the common case for conforming types, which turned out to be a bad idea. Hence, SE-0011:

  https://github.com/apple/swift-evolution/blob/master/proposals/0011-replace-typealias-associated.md

Why didn’t we just go with generics? That’s essentially what it is.

···

On Jun 30, 2016, at 10:28 AM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

On Jun 30, 2016, at 9:55 AM, David Hart via swift-evolution <swift-evolution@swift.org> wrote:

  - Doug

On 30 Jun 2016, at 15:22, Brandon Knope via swift-evolution <swift-evolution@swift.org> wrote:

But surely using two different keywords could seem confusing to many as part of the same system?

Using associatedtype in the declaration and then typealias in the conforming type just seems inconsistent and ripe for confusion. '

I am curious if any advanced Swift users still get tripped up here

Brandon

Sent from my iPad

On Jun 30, 2016, at 8:53 AM, Brent Royal-Gordon <brent@architechies.com> wrote:

On Jun 29, 2016, at 6:55 AM, Brandon Knope via swift-evolution <swift-evolution@swift.org> wrote:

What's the rationale for having associatedtype in protocols and typealias in the conforming types?

I didn't design it, but here's how I think about it: The associated type requirement merely states that there must be a type with this name meeting these criteria. `typealias` is one way to satisfy that requirement, but you can also just define a nested type with that name:

struct MyCollection {
    struct Index: Comparable { … }
}

Should you replace `struct` with `associatedtype`? No? Then why would you replace `typealias` with `associatedtype`?

--
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

They are not the same, because they aren’t type parameters to the protocol and you can’t have those type parameters vary for a given conforming type. There’s a short discussion over at

  https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#generic-protocols

and it’s been discussed on this list a number of times. It would be great if someone could turn those discussions into better text in the generics manifesto so everyone can better understand how the features differ.

  - Doug

···

On Jun 30, 2016, at 10:31 AM, Kevin Nattinger <swift@nattinger.net> wrote:

On Jun 30, 2016, at 10:28 AM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

On Jun 30, 2016, at 9:55 AM, David Hart via swift-evolution <swift-evolution@swift.org> wrote:

I don't see that as confusing. In a conforming type, he compiler is looking for a type with the same name as the associatedtype declaration. As the proposal mentions, typealias is not the only way to provide that type. It's actually logical to typealias to point the compiler to the correct type as well as it is to define a internal type with the same name from the start.

“associatedtype” used to be “typealias”, because we were trying to make the declaration in the protocol use the same spelling as the common case for conforming types, which turned out to be a bad idea. Hence, SE-0011:

  https://github.com/apple/swift-evolution/blob/master/proposals/0011-replace-typealias-associated.md

Why didn’t we just go with generics? That’s essentially what it is.

I know :) I've been following the mailing list attentively since the beginning! I was just trying to give my rational for why I think it is still logical to have typealias for conforming to the associatedtype.

···

On 30 Jun 2016, at 19:28, Douglas Gregor <dgregor@apple.com> wrote:

On Jun 30, 2016, at 9:55 AM, David Hart via swift-evolution <swift-evolution@swift.org> wrote:

I don't see that as confusing. In a conforming type, he compiler is looking for a type with the same name as the associatedtype declaration. As the proposal mentions, typealias is not the only way to provide that type. It's actually logical to typealias to point the compiler to the correct type as well as it is to define a internal type with the same name from the start.

“associatedtype” used to be “typealias”, because we were trying to make the declaration in the protocol use the same spelling as the common case for conforming types, which turned out to be a bad idea. Hence, SE-0011:

   https://github.com/apple/swift-evolution/blob/master/proposals/0011-replace-typealias-associated.md

   - Doug

On 30 Jun 2016, at 15:22, Brandon Knope via swift-evolution <swift-evolution@swift.org> wrote:

But surely using two different keywords could seem confusing to many as part of the same system?

Using associatedtype in the declaration and then typealias in the conforming type just seems inconsistent and ripe for confusion. '

I am curious if any advanced Swift users still get tripped up here

Brandon

Sent from my iPad

On Jun 30, 2016, at 8:53 AM, Brent Royal-Gordon <brent@architechies.com> wrote:

On Jun 29, 2016, at 6:55 AM, Brandon Knope via swift-evolution <swift-evolution@swift.org> wrote:

What's the rationale for having associatedtype in protocols and typealias in the conforming types?

I didn't design it, but here's how I think about it: The associated type requirement merely states that there must be a type with this name meeting these criteria. `typealias` is one way to satisfy that requirement, but you can also just define a nested type with that name:

struct MyCollection {
    struct Index: Comparable { … }
}

Should you replace `struct` with `associatedtype`? No? Then why would you replace `typealias` with `associatedtype`?

--
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