[Proposal] Associated Type and Generic One-to-One Mapping


(David Moore) #1

Hello Swift Evolution,

This may have already been discussed before, but I just came across a bothersome language aspect which reminded me to propose a solution. Currently, if we want to add generics to a protocol the only way to do so is with associated types. I am quite fine with the current approach with respect to those semantics.

There is, however, a weakness that is built in with using associated types. That weakness is the lack of associated type and generic inference. To be more clear about what I mean, take the following as an example.

protocol Foo {
    associatedtype T
}

The foregoing protocol is quite basic, but uses an associated type with the name “T.” Giving the associated type that name will illustrate the dilemma encountered later on down the pipeline.

struct Bar<T> : Foo {
    // What am I supposed to do? The name is used for both the generic and the type alias Foo needs for conformance.
    typealias T = T // Error!
}

The above illustrates a situation where we want to connect the generic, which is supposedly named appropriately, and the protocol’s associated type. There is no elegant solution for this at the moment. All I could do is the following.

struct Bar<U> : Foo {
    typealias T = U // Not nearly as readable.
}

Now, there may be a few ways to go about adding support for generic inference. The compiler as it is already does some awesome inference get when it comes to generics, so why not take it a step further? I propose the introduction of a keyword, or anything else that could work, to specify explicitly what a given type alias declaration would do when it comes to inferencing. Requiring a keyword would ensure source compatibility remains intact, and it would also make the code more readable.

I don’t know if this would be something that people could find useful, but I surely would. The implicit mapping of an associated type and a given generic by their names, would be a natural development.

Let me know if this is just useless, or if could be a potential feature.

Thank you,
David Moore


(Xiaodi Wu) #2

There could be source-breaking implications for such a feature, especially
with retroactive conformance. Therefore, I think this could be very tricky
and I'd want to be convinced that the benefits are very great to risk such
a disturbance. Here, I think the problem is rather mild, and here's why:

It is true that, in your example specifically, renaming T to U is the only
solution (that I know of, anyway). However, for any "serious" protocol P,
there's likely to be a required property of type P.T, or a function that
takes an argument of type P.T or returns a value of type P.T. Therefore,
implementing that requirement in Bar with a corresponding
property/argument/return value of type Bar.T would generally do the trick.

Have you got any real-world examples where you're running into this issue?

···

On Fri, Jun 23, 2017 at 17:03 David Moore via swift-evolution < swift-evolution@swift.org> wrote:

Hello Swift Evolution,

This may have already been discussed before, but I just came across a
bothersome language aspect which reminded me to propose a solution.
Currently, if we want to add generics to a protocol the only way to do so
is with associated types. I am quite fine with the current approach with
respect to those semantics.

There is, however, a weakness that is built in with using associated
types. That weakness is the lack of associated type and generic inference.
To be more clear about what I mean, take the following as an example.

protocol Foo {
    associatedtype T
}

The foregoing protocol is quite basic, but uses an associated type with
the name “T.” Giving the associated type that name will illustrate the
dilemma encountered later on down the pipeline.

struct Bar<T> : Foo {
    // What am I supposed to do? The name is used for both the generic and
the type alias Foo needs for conformance.
    typealias T = T // Error!
}

The above illustrates a situation where we want to connect the generic,
which is supposedly named appropriately, and the protocol’s associated
type. There is no elegant solution for this at the moment. All I could do
is the following.

struct Bar<U> : Foo {
    typealias T = U // Not nearly as readable.
}

Now, there may be a few ways to go about adding support for generic
inference. The compiler as it is already does some awesome inference get
when it comes to generics, so why not take it a step further? I propose the
introduction of a keyword, or anything else that could work, to specify
explicitly what a given type alias declaration would do when it comes to
inferencing. Requiring a keyword would ensure source compatibility remains
intact, and it would also make the code more readable.

I don’t know if this would be something that people could find useful, but
I surely would. The implicit mapping of an associated type and a given
generic by their names, would be a natural development.

Let me know if this is just useless, or if could be a potential feature.

Thank you,
David Moore
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(David Moore) #3

I do indeed have quite a few real examples of this, such prompted me to bring this up. I think this could be done without any impact to existing code, but it would require some type of keyword. Take the following as a possible prototype.

protocol Foo {
    associatedtype T
}

struct Bar<T> : Foo {
    keyword typealias T // Or really any other syntactical implementation.
}

With an opt-in method we could implement this without affecting existing code, thereby making this more viable. I will send some examples later.

···

On Jun 23, 2017, at 6:52 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

There could be source-breaking implications for such a feature, especially with retroactive conformance. Therefore, I think this could be very tricky and I'd want to be convinced that the benefits are very great to risk such a disturbance. Here, I think the problem is rather mild, and here's why:

It is true that, in your example specifically, renaming T to U is the only solution (that I know of, anyway). However, for any "serious" protocol P, there's likely to be a required property of type P.T, or a function that takes an argument of type P.T or returns a value of type P.T. Therefore, implementing that requirement in Bar with a corresponding property/argument/return value of type Bar.T would generally do the trick.

Have you got any real-world examples where you're running into this issue?

On Fri, Jun 23, 2017 at 17:03 David Moore via swift-evolution <swift-evolution@swift.org> wrote:
Hello Swift Evolution,

This may have already been discussed before, but I just came across a bothersome language aspect which reminded me to propose a solution. Currently, if we want to add generics to a protocol the only way to do so is with associated types. I am quite fine with the current approach with respect to those semantics.

There is, however, a weakness that is built in with using associated types. That weakness is the lack of associated type and generic inference. To be more clear about what I mean, take the following as an example.

protocol Foo {
    associatedtype T
}

The foregoing protocol is quite basic, but uses an associated type with the name “T.” Giving the associated type that name will illustrate the dilemma encountered later on down the pipeline.

struct Bar<T> : Foo {
    // What am I supposed to do? The name is used for both the generic and the type alias Foo needs for conformance.
    typealias T = T // Error!
}

The above illustrates a situation where we want to connect the generic, which is supposedly named appropriately, and the protocol’s associated type. There is no elegant solution for this at the moment. All I could do is the following.

struct Bar<U> : Foo {
    typealias T = U // Not nearly as readable.
}

Now, there may be a few ways to go about adding support for generic inference. The compiler as it is already does some awesome inference get when it comes to generics, so why not take it a step further? I propose the introduction of a keyword, or anything else that could work, to specify explicitly what a given type alias declaration would do when it comes to inferencing. Requiring a keyword would ensure source compatibility remains intact, and it would also make the code more readable.

I don’t know if this would be something that people could find useful, but I surely would. The implicit mapping of an associated type and a given generic by their names, would be a natural development.

Let me know if this is just useless, or if could be a potential feature.

Thank you,
David Moore
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(David Sweeris) #4

At one point there was talk of just having generic parameters automatically becoming typealiases:
struct Bar<T> : Foo {
    // `T` is automatically an implicit typealias for, well, `T`
}

Dunno if that’s still the plan (or to what degree it ever was), but it’d work for me. I don’t even think it’d break source compatibility (though it may make a lot of typealiases unneeded.

- Dave Sweeris

···

On Jun 23, 2017, at 5:28 PM, David Moore via swift-evolution <swift-evolution@swift.org> wrote:

I do indeed have quite a few real examples of this, such prompted me to bring this up. I think this could be done without any impact to existing code, but it would require some type of keyword. Take the following as a possible prototype.

protocol Foo {
    associatedtype T
}

struct Bar<T> : Foo {
    keyword typealias T // Or really any other syntactical implementation.
}

With an opt-in method we could implement this without affecting existing code, thereby making this more viable. I will send some examples later.


(Xiaodi Wu) #5

Yes, examples will be helpful.

···

On Fri, Jun 23, 2017 at 19:28 David Moore via swift-evolution < swift-evolution@swift.org> wrote:

I do indeed have quite a few real examples of this, such prompted me to
bring this up. I think this could be done without any impact to existing
code, but it would require some type of keyword. Take the following as a
possible prototype.

protocol Foo {
    associatedtype T
}

struct Bar<T> : Foo {
    keyword typealias T // Or really any other syntactical implementation.
}

With an opt-in method we could implement this without affecting existing
code, thereby making this more viable. I will send some examples later.

On Jun 23, 2017, at 6:52 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

There could be source-breaking implications for such a feature, especially
with retroactive conformance. Therefore, I think this could be very tricky
and I'd want to be convinced that the benefits are very great to risk such
a disturbance. Here, I think the problem is rather mild, and here's why:

It is true that, in your example specifically, renaming T to U is the only
solution (that I know of, anyway). However, for any "serious" protocol P,
there's likely to be a required property of type P.T, or a function that
takes an argument of type P.T or returns a value of type P.T. Therefore,
implementing that requirement in Bar with a corresponding
property/argument/return value of type Bar.T would generally do the trick.

Have you got any real-world examples where you're running into this issue?

On Fri, Jun 23, 2017 at 17:03 David Moore via swift-evolution < > swift-evolution@swift.org> wrote:

Hello Swift Evolution,

This may have already been discussed before, but I just came across a
bothersome language aspect which reminded me to propose a solution.
Currently, if we want to add generics to a protocol the only way to do so
is with associated types. I am quite fine with the current approach with
respect to those semantics.

There is, however, a weakness that is built in with using associated
types. That weakness is the lack of associated type and generic inference.
To be more clear about what I mean, take the following as an example.

protocol Foo {
    associatedtype T
}

The foregoing protocol is quite basic, but uses an associated type with
the name “T.” Giving the associated type that name will illustrate the
dilemma encountered later on down the pipeline.

struct Bar<T> : Foo {
    // What am I supposed to do? The name is used for both the generic
and the type alias Foo needs for conformance.
    typealias T = T // Error!
}

The above illustrates a situation where we want to connect the generic,
which is supposedly named appropriately, and the protocol’s associated
type. There is no elegant solution for this at the moment. All I could do
is the following.

struct Bar<U> : Foo {
    typealias T = U // Not nearly as readable.
}

Now, there may be a few ways to go about adding support for generic
inference. The compiler as it is already does some awesome inference get
when it comes to generics, so why not take it a step further? I propose the
introduction of a keyword, or anything else that could work, to specify
explicitly what a given type alias declaration would do when it comes to
inferencing. Requiring a keyword would ensure source compatibility remains
intact, and it would also make the code more readable.

I don’t know if this would be something that people could find useful,
but I surely would. The implicit mapping of an associated type and a given
generic by their names, would be a natural development.

Let me know if this is just useless, or if could be a potential feature.

Thank you,
David Moore
_______________________________________________
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


(Jaden Geller) #6

I’ve run into this issue many times in the real world as well. For example, consider the following protocol:

protocol OptionalType {
    associatedtype Wrapped
}

It is not possible to conform `Optional` to this protocol because its generic type is already named `Wrapped`. Only when the associated type can be inferred is conformance possible.

I definitely think we need a solution, but I don’t know what that solution should be.

Cheers,
Jaden Geller

···

On Jun 23, 2017, at 3:52 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

There could be source-breaking implications for such a feature, especially with retroactive conformance. Therefore, I think this could be very tricky and I'd want to be convinced that the benefits are very great to risk such a disturbance. Here, I think the problem is rather mild, and here's why:

It is true that, in your example specifically, renaming T to U is the only solution (that I know of, anyway). However, for any "serious" protocol P, there's likely to be a required property of type P.T, or a function that takes an argument of type P.T or returns a value of type P.T. Therefore, implementing that requirement in Bar with a corresponding property/argument/return value of type Bar.T would generally do the trick.

Have you got any real-world examples where you're running into this issue?

On Fri, Jun 23, 2017 at 17:03 David Moore via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Hello Swift Evolution,

This may have already been discussed before, but I just came across a bothersome language aspect which reminded me to propose a solution. Currently, if we want to add generics to a protocol the only way to do so is with associated types. I am quite fine with the current approach with respect to those semantics.

There is, however, a weakness that is built in with using associated types. That weakness is the lack of associated type and generic inference. To be more clear about what I mean, take the following as an example.

protocol Foo {
    associatedtype T
}

The foregoing protocol is quite basic, but uses an associated type with the name “T.” Giving the associated type that name will illustrate the dilemma encountered later on down the pipeline.

struct Bar<T> : Foo {
    // What am I supposed to do? The name is used for both the generic and the type alias Foo needs for conformance.
    typealias T = T // Error!
}

The above illustrates a situation where we want to connect the generic, which is supposedly named appropriately, and the protocol’s associated type. There is no elegant solution for this at the moment. All I could do is the following.

struct Bar<U> : Foo {
    typealias T = U // Not nearly as readable.
}

Now, there may be a few ways to go about adding support for generic inference. The compiler as it is already does some awesome inference get when it comes to generics, so why not take it a step further? I propose the introduction of a keyword, or anything else that could work, to specify explicitly what a given type alias declaration would do when it comes to inferencing. Requiring a keyword would ensure source compatibility remains intact, and it would also make the code more readable.

I don’t know if this would be something that people could find useful, but I surely would. The implicit mapping of an associated type and a given generic by their names, would be a natural development.

Let me know if this is just useless, or if could be a potential feature.

Thank you,
David Moore
_______________________________________________
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


(David Moore) #7

protocol Bondable {
associatedtype Key
associatedtype Value

static func new\(\) \-&gt; Self

func value\(forKey key: Key\) \-&gt; Value?

mutating func updateValue\(\_ value: Value?, forKey key: Key\)

}

extension Dictionary: Bondable {
static func new() -> Dictionary<Key, Value> {
return Dictionary<Key, Value>()
}

func value\(forKey key: Key\) \-&gt; Value? \{
    return self\[key\]
\}

mutating func updateValue\(\_ value: Value?, forKey key: Key\) \{
    self\[key\] = value
\}

}

struct Bridge<A, B> {
struct Getter {
var transform: ((B) -> A?)
}

struct Setter \{
    var transform: \(\(A\) \-&gt; B?\)
\}

var get: Getter
var set: Setter

}

protocol Bonding {
associatedtype Dictionary: Bondable
associatedtype Value

var key: Dictionary\.Key \{ get set \}

var bridge: Bridge&lt;Value, Dictionary\.Value&gt; \{ get set \}

func value\(from aDictionary: Dictionary, using set: Bridge&lt;Value, Dictionary\.Value&gt;\.Getter\) \-&gt; Value?

func addValue\(\_ value: Value, to aDictionary: inout Dictionary, using get: Bridge&lt;Value, Dictionary\.Value&gt;\.Setter\)

}

extension Bonding {

func value\(from aDictionary: Dictionary, using get: Bridge&lt;Value, Dictionary\.Value&gt;\.Getter\) \-&gt; Value? \{
    if let value = aDictionary\.value\(forKey: key\) \{
        return get\.transform\(value\)
    \} else \{
        return nil

    \}
\}

func addValue\(\_ value: Value, to aDictionary: inout Dictionary, using set: Bridge&lt;Value, Dictionary\.Value&gt;\.Setter\) \{
    aDictionary\.updateValue\(set\.transform\(value\), forKey: key\)
\}

}

struct ComplexBond<__Dictionary: Bondable, __Value>: Bonding {
typealias Dictionary = __Dictionary
typealias Value = __Value

var key: \_\_Dictionary\.Key

var bridge: Bridge&lt;\_\_Value, \_\_Dictionary\.Value&gt;

}

The above is an example implementation of the `Bonding` protocol, where the preexisting names of the associated types, `Dictionary` and `Value`, are already appropriately named. It would be great if I could just add a simple keyword prefixing the `typealias` keyword which would enable the inferencing behavior.

···

On Jun 23, 2017, 8:36 PM -0400, Xiaodi Wu <xiaodi.wu@gmail.com>, wrote:

Yes, examples will be helpful.

> On Fri, Jun 23, 2017 at 19:28 David Moore via swift-evolution <swift-evolution@swift.org> wrote:
> > I do indeed have quite a few real examples of this, such prompted me to bring this up. I think this could be done without any impact to existing code, but it would require some type of keyword. Take the following as a possible prototype.
> >
> > protocol Foo {
> > associatedtype T
> > }
> >
> > struct Bar<T> : Foo {
> > keyword typealias T // Or really any other syntactical implementation.
> > }
> >
> > With an opt-in method we could implement this without affecting existing code, thereby making this more viable. I will send some examples later.
> >
> > On Jun 23, 2017, at 6:52 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:
> >
> > > There could be source-breaking implications for such a feature, especially with retroactive conformance. Therefore, I think this could be very tricky and I'd want to be convinced that the benefits are very great to risk such a disturbance. Here, I think the problem is rather mild, and here's why:
> > >
> > > It is true that, in your example specifically, renaming T to U is the only solution (that I know of, anyway). However, for any "serious" protocol P, there's likely to be a required property of type P.T, or a function that takes an argument of type P.T or returns a value of type P.T. Therefore, implementing that requirement in Bar with a corresponding property/argument/return value of type Bar.T would generally do the trick.
> > >
> > > Have you got any real-world examples where you're running into this issue?
> > >
> > > > On Fri, Jun 23, 2017 at 17:03 David Moore via swift-evolution <swift-evolution@swift.org> wrote:
> > > > > Hello Swift Evolution,
> > > > >
> > > > > This may have already been discussed before, but I just came across a bothersome language aspect which reminded me to propose a solution. Currently, if we want to add generics to a protocol the only way to do so is with associated types. I am quite fine with the current approach with respect to those semantics.
> > > > >
> > > > > There is, however, a weakness that is built in with using associated types. That weakness is the lack of associated type and generic inference. To be more clear about what I mean, take the following as an example.
> > > > >
> > > > > protocol Foo {
> > > > > associatedtype T
> > > > > }
> > > > >
> > > > > The foregoing protocol is quite basic, but uses an associated type with the name “T.” Giving the associated type that name will illustrate the dilemma encountered later on down the pipeline.
> > > > >
> > > > > struct Bar<T> : Foo {
> > > > > // What am I supposed to do? The name is used for both the generic and the type alias Foo needs for conformance.
> > > > > typealias T = T // Error!
> > > > > }
> > > > >
> > > > > The above illustrates a situation where we want to connect the generic, which is supposedly named appropriately, and the protocol’s associated type. There is no elegant solution for this at the moment. All I could do is the following.
> > > > >
> > > > > struct Bar<U> : Foo {
> > > > > typealias T = U // Not nearly as readable.
> > > > > }
> > > > >
> > > > > Now, there may be a few ways to go about adding support for generic inference. The compiler as it is already does some awesome inference get when it comes to generics, so why not take it a step further? I propose the introduction of a keyword, or anything else that could work, to specify explicitly what a given type alias declaration would do when it comes to inferencing. Requiring a keyword would ensure source compatibility remains intact, and it would also make the code more readable.
> > > > >
> > > > > I don’t know if this would be something that people could find useful, but I surely would. The implicit mapping of an associated type and a given generic by their names, would be a natural development.
> > > > >
> > > > > Let me know if this is just useless, or if could be a potential feature.
> > > > >
> > > > > Thank you,
> > > > > David Moore
> > > > > _______________________________________________
> > > > > 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


(Xiaodi Wu) #8

For every Bar.T that is currently distinct from Foo.T, this would be
source-breaking.

···

On Sat, Jun 24, 2017 at 01:51 David Sweeris via swift-evolution < swift-evolution@swift.org> wrote:

> On Jun 23, 2017, at 5:28 PM, David Moore via swift-evolution < > swift-evolution@swift.org> wrote:
>
> I do indeed have quite a few real examples of this, such prompted me to
bring this up. I think this could be done without any impact to existing
code, but it would require some type of keyword. Take the following as a
possible prototype.
>
> protocol Foo {
> associatedtype T
> }
>
> struct Bar<T> : Foo {
> keyword typealias T // Or really any other syntactical
implementation.
> }
>
> With an opt-in method we could implement this without affecting existing
code, thereby making this more viable. I will send some examples later.

At one point there was talk of just having generic parameters
automatically becoming typealiases:
struct Bar<T> : Foo {
    // `T` is automatically an implicit typealias for, well, `T`
}

Dunno if that’s still the plan (or to what degree it ever was), but it’d
work for me. I don’t even think it’d break source compatibility (though it
may make a lot of typealiases unneeded.

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


(Xiaodi Wu) #9

protocol Bondable {

    associatedtype Key

    associatedtype Value

    static func new() -> Self

    func value(forKey key: Key) -> Value?

    mutating func updateValue(_ value: Value?, forKey key: Key)

}

extension Dictionary: Bondable {

    static func new() -> Dictionary<Key, Value> {

        return Dictionary<Key, Value>()

    }

    func value(forKey key: Key) -> Value? {

        return self[key]

    }

    mutating func updateValue(_ value: Value?, forKey key: Key) {

        self[key] = value

    }

}

struct Bridge<A, B> {

    struct Getter {

        var transform: ((B) -> A?)

    }

    struct Setter {

        var transform: ((A) -> B?)

    }

    var get: Getter

    var set: Setter

}

protocol Bonding {

    associatedtype Dictionary: Bondable

    associatedtype Value

    var key: Dictionary.Key { get set }

    var bridge: Bridge<Value, Dictionary.Value> { get set }

    func value(from aDictionary: Dictionary, using set: Bridge<Value,
Dictionary.Value>.Getter) -> Value?

    func addValue(_ value: Value, to aDictionary: inout Dictionary, using
get: Bridge<Value, Dictionary.Value>.Setter)

}

extension Bonding {

    func value(from aDictionary: Dictionary, using get: Bridge<Value,
Dictionary.Value>.Getter) -> Value? {

        if let value = aDictionary.value(forKey: key) {

            return get.transform(value)

        } else {

            return nil

        }

    }

    func addValue(_ value: Value, to aDictionary: inout Dictionary, using
set: Bridge<Value, Dictionary.Value>.Setter) {

        aDictionary.updateValue(set.transform(value), forKey: key)

    }

}

struct ComplexBond<__Dictionary: Bondable, __Value>: Bonding {

    typealias Dictionary = __Dictionary

    typealias Value = __Value

    var key: __Dictionary.Key

    var bridge: Bridge<__Value, __Dictionary.Value>

}

The above is an example implementation of the `Bonding` protocol, where
the preexisting names of the associated types, `Dictionary` and `Value`,
are already appropriately named. It would be great if I could just add a
simple keyword prefixing the `typealias` keyword which would enable the
inferencing behavior.

You already don't need to use a typealias for `Value`. It can already be
inferred from the type of `bridge`.

struct ComplexBond<__Dictionary: Bondable, Value>: Bonding {
  typealias Dictionary = __Dictionary
  var key: Dictionary.Key
  var bridge: Bridge<Value, Dictionary.Value>
}

// This compiles.

The issue with `Dictionary` and `__Dictionary` is interesting, and here is
my analysis:

The thing is, you don't actually need `Dictionary` to be a typealias for
`__Dictionary` _in order for `ComplexBond` to conform to `Bonding`_ (though
you may require this for the semantics of `ComplexBond` itself). For
instance, I can instead declare a `ComplexBond2` as follows:

struct ComplexBond2<__Dictionary: Bondable, Value, __AnotherDictionary:
> : Bonding

where __Dictionary.Key == __AnotherDictionary.Key, __Dictionary.Value ==
__AnotherDictionary.Value {
  typealias Dictionary = __AnotherDictionary
  var key: __Dictionary.Key
  var bridge: Bridge<Value, __Dictionary.Value>
}

Put another way, for the purposes of conformance, it only matters that
`__Dictionary.Key` is the same type as `Dictionary.Key` and that
`__Dictionary.Value` is the same type as `Dictionary.Value`, but
`ComplexBond.__Dictionary` and `Bonding.Dictionary` are not required _by
the protocol_ to be the same type. Of course, if `ComplexBond` had to
implement some protocol requirement by which you could infer that
`__Dictionary` must be the same type as `Dictionary`, then that inference
would be possible too without a typealias.

Put another way, the fact that `typealias Dictionary = __Dictionary` is
required here is not merely a reflection of some shortcoming in the
expressiveness of the language: it reflects the fact that this relationship
cannot be inferred because the relationship doesn't have to be that way--as
far as conformance of `ComplexBond` to `Bonding` is concerned. Instead,
with that statement, you're making a _choice_ based on the desired
semantics for `ComplexBond`, a choice that is not forced upon you by the
protocol to which it conforms. In that sense, it is actually useful that
Swift prevents you from naming both `Dictionary` and `__Dictionary` the
same thing: you are reminded that the relationship between the two is a
choice of the conforming type, not an inevitability of protocol
conformance; by contrast, if some requirement *does* make the relationship
an inevitability, such a typealias is not required and you *can* name the
two with the same name (as is the case with `Value`).

···

On Fri, Jun 23, 2017 at 8:29 PM, David Moore via swift-evolution < swift-evolution@swift.org> wrote:

On Jun 23, 2017, 8:36 PM -0400, Xiaodi Wu <xiaodi.wu@gmail.com>, wrote:

Yes, examples will be helpful.

On Fri, Jun 23, 2017 at 19:28 David Moore via swift-evolution < > swift-evolution@swift.org> wrote:

I do indeed have quite a few real examples of this, such prompted me to
bring this up. I think this could be done without any impact to existing
code, but it would require some type of keyword. Take the following as a
possible prototype.

protocol Foo {
    associatedtype T
}

struct Bar<T> : Foo {
    keyword typealias T // Or really any other syntactical implementation.
}

With an opt-in method we could implement this without affecting existing
code, thereby making this more viable. I will send some examples later.

On Jun 23, 2017, at 6:52 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

There could be source-breaking implications for such a feature,
especially with retroactive conformance. Therefore, I think this could be
very tricky and I'd want to be convinced that the benefits are very great
to risk such a disturbance. Here, I think the problem is rather mild, and
here's why:

It is true that, in your example specifically, renaming T to U is the
only solution (that I know of, anyway). However, for any "serious" protocol
P, there's likely to be a required property of type P.T, or a function that
takes an argument of type P.T or returns a value of type P.T. Therefore,
implementing that requirement in Bar with a corresponding
property/argument/return value of type Bar.T would generally do the trick.

Have you got any real-world examples where you're running into this issue?

On Fri, Jun 23, 2017 at 17:03 David Moore via swift-evolution < >> swift-evolution@swift.org> wrote:

Hello Swift Evolution,

This may have already been discussed before, but I just came across a
bothersome language aspect which reminded me to propose a solution.
Currently, if we want to add generics to a protocol the only way to do so
is with associated types. I am quite fine with the current approach with
respect to those semantics.

There is, however, a weakness that is built in with using associated
types. That weakness is the lack of associated type and generic inference.
To be more clear about what I mean, take the following as an example.

protocol Foo {
    associatedtype T
}

The foregoing protocol is quite basic, but uses an associated type with
the name “T.” Giving the associated type that name will illustrate the
dilemma encountered later on down the pipeline.

struct Bar<T> : Foo {
    // What am I supposed to do? The name is used for both the generic
and the type alias Foo needs for conformance.
    typealias T = T // Error!
}

The above illustrates a situation where we want to connect the generic,
which is supposedly named appropriately, and the protocol’s associated
type. There is no elegant solution for this at the moment. All I could do
is the following.

struct Bar<U> : Foo {
    typealias T = U // Not nearly as readable.
}

Now, there may be a few ways to go about adding support for generic
inference. The compiler as it is already does some awesome inference get
when it comes to generics, so why not take it a step further? I propose the
introduction of a keyword, or anything else that could work, to specify
explicitly what a given type alias declaration would do when it comes to
inferencing. Requiring a keyword would ensure source compatibility remains
intact, and it would also make the code more readable.

I don’t know if this would be something that people could find useful,
but I surely would. The implicit mapping of an associated type and a given
generic by their names, would be a natural development.

Let me know if this is just useless, or if could be a potential feature.

Thank you,
David Moore
_______________________________________________
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


(Víctor Pimentel) #10

Automatic implicit type aliases sounds the ideal solution, at least from the point of view of the programmer.

If that is too difficult or costly to the compiler, I don't think adding another keyword would be a good solution or compromise. Maybe it can be also be solved by supporting some way of referring to Bar.T and Foo.T explicitly:

struct Bar<T> : Foo {
   typealias T = Bar.T
}

Or:

struct Bar<T> : Foo {
   typealias Foo.T = Bar.T
}

Or:

struct Bar<T> : Foo {
   typealias Foo.T = T
}

The compiler could help by suggesting fix-it if encountered with the original non-compiling code.

···

On 24 Jun 2017, at 08:50, David Sweeris via swift-evolution <swift-evolution@swift.org> wrote:

On Jun 23, 2017, at 5:28 PM, David Moore via swift-evolution <swift-evolution@swift.org> wrote:

I do indeed have quite a few real examples of this, such prompted me to bring this up. I think this could be done without any impact to existing code, but it would require some type of keyword. Take the following as a possible prototype.

protocol Foo {
   associatedtype T
}

struct Bar<T> : Foo {
   keyword typealias T // Or really any other syntactical implementation.
}

With an opt-in method we could implement this without affecting existing code, thereby making this more viable. I will send some examples later.

At one point there was talk of just having generic parameters automatically becoming typealiases:
struct Bar<T> : Foo {
   // `T` is automatically an implicit typealias for, well, `T`
}

Dunno if that’s still the plan (or to what degree it ever was), but it’d work for me. I don’t even think it’d break source compatibility (though it may make a lot of typealiases unneeded.

- Dave Sweeris

--
Víctor Pimentel


(Matthew Johnson) #11

I’ve run into this issue many times in the real world as well. For example, consider the following protocol:

protocol OptionalType {
    associatedtype Wrapped
}

It is not possible to conform `Optional` to this protocol because its generic type is already named `Wrapped`. Only when the associated type can be inferred is conformance possible.

I definitely think we need a solution, but I don’t know what that solution should be.

I agree. I have run into this as well and have been frustrated by it. It isn’t clear to me what the best solution is but I’d love to see one that could make it into a 4.x release.

···

On Jun 27, 2017, at 12:39 PM, Jaden Geller via swift-evolution <swift-evolution@swift.org> wrote:

Cheers,
Jaden Geller

On Jun 23, 2017, at 3:52 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

There could be source-breaking implications for such a feature, especially with retroactive conformance. Therefore, I think this could be very tricky and I'd want to be convinced that the benefits are very great to risk such a disturbance. Here, I think the problem is rather mild, and here's why:

It is true that, in your example specifically, renaming T to U is the only solution (that I know of, anyway). However, for any "serious" protocol P, there's likely to be a required property of type P.T, or a function that takes an argument of type P.T or returns a value of type P.T. Therefore, implementing that requirement in Bar with a corresponding property/argument/return value of type Bar.T would generally do the trick.

Have you got any real-world examples where you're running into this issue?

On Fri, Jun 23, 2017 at 17:03 David Moore via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Hello Swift Evolution,

This may have already been discussed before, but I just came across a bothersome language aspect which reminded me to propose a solution. Currently, if we want to add generics to a protocol the only way to do so is with associated types. I am quite fine with the current approach with respect to those semantics.

There is, however, a weakness that is built in with using associated types. That weakness is the lack of associated type and generic inference. To be more clear about what I mean, take the following as an example.

protocol Foo {
    associatedtype T
}

The foregoing protocol is quite basic, but uses an associated type with the name “T.” Giving the associated type that name will illustrate the dilemma encountered later on down the pipeline.

struct Bar<T> : Foo {
    // What am I supposed to do? The name is used for both the generic and the type alias Foo needs for conformance.
    typealias T = T // Error!
}

The above illustrates a situation where we want to connect the generic, which is supposedly named appropriately, and the protocol’s associated type. There is no elegant solution for this at the moment. All I could do is the following.

struct Bar<U> : Foo {
    typealias T = U // Not nearly as readable.
}

Now, there may be a few ways to go about adding support for generic inference. The compiler as it is already does some awesome inference get when it comes to generics, so why not take it a step further? I propose the introduction of a keyword, or anything else that could work, to specify explicitly what a given type alias declaration would do when it comes to inferencing. Requiring a keyword would ensure source compatibility remains intact, and it would also make the code more readable.

I don’t know if this would be something that people could find useful, but I surely would. The implicit mapping of an associated type and a given generic by their names, would be a natural development.

Let me know if this is just useless, or if could be a potential feature.

Thank you,
David Moore
_______________________________________________
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


(David Sweeris) #12

Would that even compile? I thought I'd remembered getting an "illegal redefinition of T" or some such error, but maybe I'm misremembering (plus, I haven't tried in a really long time).

- Dave Sweeris

···

On Jun 24, 2017, at 08:48, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

For every Bar.T that is currently distinct from Foo.T, this would be source-breaking.

On Sat, Jun 24, 2017 at 01:51 David Sweeris via swift-evolution <swift-evolution@swift.org> wrote:

> On Jun 23, 2017, at 5:28 PM, David Moore via swift-evolution <swift-evolution@swift.org> wrote:
>
> I do indeed have quite a few real examples of this, such prompted me to bring this up. I think this could be done without any impact to existing code, but it would require some type of keyword. Take the following as a possible prototype.
>
> protocol Foo {
> associatedtype T
> }
>
> struct Bar<T> : Foo {
> keyword typealias T // Or really any other syntactical implementation.
> }
>
> With an opt-in method we could implement this without affecting existing code, thereby making this more viable. I will send some examples later.

At one point there was talk of just having generic parameters automatically becoming typealiases:
struct Bar<T> : Foo {
    // `T` is automatically an implicit typealias for, well, `T`
}

Dunno if that’s still the plan (or to what degree it ever was), but it’d work for me. I don’t even think it’d break source compatibility (though it may make a lot of typealiases unneeded.

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


(Xiaodi Wu) #13

Would that even compile? I thought I'd remembered getting an "illegal
redefinition of T" or some such error, but maybe I'm misremembering (plus,
I haven't tried in a really long time).

There is no redefinition; it's just simple shadowing.

protocol P {
  associatedtype T
  func foo() -> T
}

struct S<T> : P {
  func foo() -> Int {
    return 42
  }
  func bar(_ x: T) -> T {
    return x
  }
}

S<String>().foo() // P.T is Int
S<String>().bar("42") // S.T is String

- Dave Sweeris

···

On Sat, Jun 24, 2017 at 12:09 PM, David Sweeris <davesweeris@mac.com> wrote:

On Jun 24, 2017, at 08:48, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

For every Bar.T that is currently distinct from Foo.T, this would be
source-breaking.
On Sat, Jun 24, 2017 at 01:51 David Sweeris via swift-evolution < > swift-evolution@swift.org> wrote:

> On Jun 23, 2017, at 5:28 PM, David Moore via swift-evolution < >> swift-evolution@swift.org> wrote:
>
> I do indeed have quite a few real examples of this, such prompted me to
bring this up. I think this could be done without any impact to existing
code, but it would require some type of keyword. Take the following as a
possible prototype.
>
> protocol Foo {
> associatedtype T
> }
>
> struct Bar<T> : Foo {
> keyword typealias T // Or really any other syntactical
implementation.
> }
>
> With an opt-in method we could implement this without affecting
existing code, thereby making this more viable. I will send some examples
later.

At one point there was talk of just having generic parameters
automatically becoming typealiases:
struct Bar<T> : Foo {
    // `T` is automatically an implicit typealias for, well, `T`
}

Dunno if that’s still the plan (or to what degree it ever was), but it’d
work for me. I don’t even think it’d break source compatibility (though it
may make a lot of typealiases unneeded.

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


(David Moore) #14

The point of the example setup I sent, is to provide a simple method for setting and/or getting values from dictionary-like types. For example, I can create a Bond between a dictionary type of [String: Any] and a value type of Foo (some class or struct). The code I sent omits some or the more primitive types in the implementation. There is another struct called Bond, and it relies on solely a single dictionary type. The point is to take a given dictionary and get or set a value. There are to be no explicitly stated generic constraints on the value type because the point is to convert values.

I still think there are plenty of benefits to associated type and generic type inferencing. The use case I have is one where it would be really helpful, but the actual example I provided cannot be justification alone. There really should be some sort of method, at the very least, to disambiguate a generic type from that of a required typealias. The language would greatly benefit from such a feature.

···

On Jun 24, 2017, at 9:41 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Fri, Jun 23, 2017 at 8:29 PM, David Moore via swift-evolution <swift-evolution@swift.org> wrote:

protocol Bondable {
    associatedtype Key
    associatedtype Value
    
    static func new() -> Self
    
    func value(forKey key: Key) -> Value?
    
    mutating func updateValue(_ value: Value?, forKey key: Key)
}

extension Dictionary: Bondable {
    static func new() -> Dictionary<Key, Value> {
        return Dictionary<Key, Value>()
    }
    
    func value(forKey key: Key) -> Value? {
        return self[key]
    }
    
    mutating func updateValue(_ value: Value?, forKey key: Key) {
        self[key] = value
    }
}

struct Bridge<A, B> {
    struct Getter {
        var transform: ((B) -> A?)
    }
    
    struct Setter {
        var transform: ((A) -> B?)
    }
    
    var get: Getter
    var set: Setter
}

protocol Bonding {
    associatedtype Dictionary: Bondable
    associatedtype Value
    
    var key: Dictionary.Key { get set }
    
    var bridge: Bridge<Value, Dictionary.Value> { get set }
    
    func value(from aDictionary: Dictionary, using set: Bridge<Value, Dictionary.Value>.Getter) -> Value?
    
    func addValue(_ value: Value, to aDictionary: inout Dictionary, using get: Bridge<Value, Dictionary.Value>.Setter)
}

extension Bonding {
    
    func value(from aDictionary: Dictionary, using get: Bridge<Value, Dictionary.Value>.Getter) -> Value? {
        if let value = aDictionary.value(forKey: key) {
            return get.transform(value)
        } else {
            return nil
            
        }
    }
    
    func addValue(_ value: Value, to aDictionary: inout Dictionary, using set: Bridge<Value, Dictionary.Value>.Setter) {
        aDictionary.updateValue(set.transform(value), forKey: key)
    }
}

struct ComplexBond<__Dictionary: Bondable, __Value>: Bonding {
    typealias Dictionary = __Dictionary
    typealias Value = __Value
    
    var key: __Dictionary.Key
    
    var bridge: Bridge<__Value, __Dictionary.Value>
}

The above is an example implementation of the `Bonding` protocol, where the preexisting names of the associated types, `Dictionary` and `Value`, are already appropriately named. It would be great if I could just add a simple keyword prefixing the `typealias` keyword which would enable the inferencing behavior.

You already don't need to use a typealias for `Value`. It can already be inferred from the type of `bridge`.

struct ComplexBond<__Dictionary: Bondable, Value>: Bonding {
  typealias Dictionary = __Dictionary
  var key: Dictionary.Key
  var bridge: Bridge<Value, Dictionary.Value>
}

// This compiles.

The issue with `Dictionary` and `__Dictionary` is interesting, and here is my analysis:

The thing is, you don't actually need `Dictionary` to be a typealias for `__Dictionary` _in order for `ComplexBond` to conform to `Bonding`_ (though you may require this for the semantics of `ComplexBond` itself). For instance, I can instead declare a `ComplexBond2` as follows:

struct ComplexBond2<__Dictionary: Bondable, Value, __AnotherDictionary: Bondable>: Bonding
where __Dictionary.Key == __AnotherDictionary.Key, __Dictionary.Value == __AnotherDictionary.Value {
  typealias Dictionary = __AnotherDictionary
  var key: __Dictionary.Key
  var bridge: Bridge<Value, __Dictionary.Value>
}

Put another way, for the purposes of conformance, it only matters that `__Dictionary.Key` is the same type as `Dictionary.Key` and that `__Dictionary.Value` is the same type as `Dictionary.Value`, but `ComplexBond.__Dictionary` and `Bonding.Dictionary` are not required _by the protocol_ to be the same type. Of course, if `ComplexBond` had to implement some protocol requirement by which you could infer that `__Dictionary` must be the same type as `Dictionary`, then that inference would be possible too without a typealias.

Put another way, the fact that `typealias Dictionary = __Dictionary` is required here is not merely a reflection of some shortcoming in the expressiveness of the language: it reflects the fact that this relationship cannot be inferred because the relationship doesn't have to be that way--as far as conformance of `ComplexBond` to `Bonding` is concerned. Instead, with that statement, you're making a _choice_ based on the desired semantics for `ComplexBond`, a choice that is not forced upon you by the protocol to which it conforms. In that sense, it is actually useful that Swift prevents you from naming both `Dictionary` and `__Dictionary` the same thing: you are reminded that the relationship between the two is a choice of the conforming type, not an inevitability of protocol conformance; by contrast, if some requirement *does* make the relationship an inevitability, such a typealias is not required and you *can* name the two with the same name (as is the case with `Value`).

On Jun 23, 2017, 8:36 PM -0400, Xiaodi Wu <xiaodi.wu@gmail.com>, wrote:
Yes, examples will be helpful.

On Fri, Jun 23, 2017 at 19:28 David Moore via swift-evolution <swift-evolution@swift.org> wrote:
I do indeed have quite a few real examples of this, such prompted me to bring this up. I think this could be done without any impact to existing code, but it would require some type of keyword. Take the following as a possible prototype.

protocol Foo {
    associatedtype T
}

struct Bar<T> : Foo {
    keyword typealias T // Or really any other syntactical implementation.
}

With an opt-in method we could implement this without affecting existing code, thereby making this more viable. I will send some examples later.

On Jun 23, 2017, at 6:52 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

There could be source-breaking implications for such a feature, especially with retroactive conformance. Therefore, I think this could be very tricky and I'd want to be convinced that the benefits are very great to risk such a disturbance. Here, I think the problem is rather mild, and here's why:

It is true that, in your example specifically, renaming T to U is the only solution (that I know of, anyway). However, for any "serious" protocol P, there's likely to be a required property of type P.T, or a function that takes an argument of type P.T or returns a value of type P.T. Therefore, implementing that requirement in Bar with a corresponding property/argument/return value of type Bar.T would generally do the trick.

Have you got any real-world examples where you're running into this issue?

On Fri, Jun 23, 2017 at 17:03 David Moore via swift-evolution <swift-evolution@swift.org> wrote:
Hello Swift Evolution,

This may have already been discussed before, but I just came across a bothersome language aspect which reminded me to propose a solution. Currently, if we want to add generics to a protocol the only way to do so is with associated types. I am quite fine with the current approach with respect to those semantics.

There is, however, a weakness that is built in with using associated types. That weakness is the lack of associated type and generic inference. To be more clear about what I mean, take the following as an example.

protocol Foo {
    associatedtype T
}

The foregoing protocol is quite basic, but uses an associated type with the name “T.” Giving the associated type that name will illustrate the dilemma encountered later on down the pipeline.

struct Bar<T> : Foo {
    // What am I supposed to do? The name is used for both the generic and the type alias Foo needs for conformance.
    typealias T = T // Error!
}

The above illustrates a situation where we want to connect the generic, which is supposedly named appropriately, and the protocol’s associated type. There is no elegant solution for this at the moment. All I could do is the following.

struct Bar<U> : Foo {
    typealias T = U // Not nearly as readable.
}

Now, there may be a few ways to go about adding support for generic inference. The compiler as it is already does some awesome inference get when it comes to generics, so why not take it a step further? I propose the introduction of a keyword, or anything else that could work, to specify explicitly what a given type alias declaration would do when it comes to inferencing. Requiring a keyword would ensure source compatibility remains intact, and it would also make the code more readable.

I don’t know if this would be something that people could find useful, but I surely would. The implicit mapping of an associated type and a given generic by their names, would be a natural development.

Let me know if this is just useless, or if could be a potential feature.

Thank you,
David Moore
_______________________________________________
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


(David Moore) #15

There are a few ways in which this issue could be addressed. The first, and most desirable approach in my opinion, would be full inferencing of a given associatedtype and a generic. An example of the foregoing would be the following:

protocol Foo {
associatedtype ABC
}

struct Bar<ABC> : Foo {
// Would normally require some sort of workaround to complete the typealias implementation of the protocol’s associatedtype, but it should be inferred in this case because there is no explicit typealias statement.
}

The inferencing would indeed take place in the above example. But now let’s consider the possibility of breaking source compatibility, as in, is this compatible or not?

struct Bar<ABC>: Foo {
typealias ABC = ArbitraryType // An inference would not take place here because there’s nothing to infer. The associated type `ABC` is explicitly defined as being `ArbitraryType`.
}

The above method shall be referred to as Option #1. It would seem like Option #1 is source compatible, in addition to solving the original problem, and potentially introduces some connivence to protocol conformance. For all existing implementations of associatedtypes and so on, I don’t think Option #1 affects them at all, unless I’m completely missing something. So Option #1 seems like a good candidate.

Onto Option #2, the idea of using base types to express more explicit definitions to solve the initial problem. When it comes to using a base type to correctly disambiguate these types of situations, it may be familiar to some who like a more concrete implementation, although it eliminates possible convenience, but still requires knowledge. Options #2 would look something like the following.

protocol Foo {
associatedtype ABC
}

struct Bar<ABC>: Foo {
typealias Foo.ABC = Bar.ABC // Quite explicit and communicates the solution clearly.
}

Options #2, as you can see above, would also be source compatible because it would not impose on already defined typealias’ or other implementations. This could be an opt-in feature. However, I don’t know if it is as nice as just pure inference, which doesn’t seem too much more difficult than this would be, but I’m not sure about that.

There is also a third option (referred to as Option #3), which could be the combination of both Option #1 and Option #2. However, there may be some syntactically-based issues that can arise in such a situation.

Let me know what everyone thinks about these possible solutions, they are by no means concretely defined as of this time, but they could be useful.

···

On Jun 27, 2017, 2:08 PM -0400, Matthew Johnson via swift-evolution <swift-evolution@swift.org>, wrote:

> On Jun 27, 2017, at 12:39 PM, Jaden Geller via swift-evolution <swift-evolution@swift.org> wrote:
>
> I’ve run into this issue many times in the real world as well. For example, consider the following protocol:
>
> protocol OptionalType {
> associatedtype Wrapped
> }
>
> It is not possible to conform `Optional` to this protocol because its generic type is already named `Wrapped`. Only when the associated type can be inferred is conformance possible.
>
> I definitely think we need a solution, but I don’t know what that solution should be.

I agree. I have run into this as well and have been frustrated by it. It isn’t clear to me what the best solution is but I’d love to see one that could make it into a 4.x release.

>
> Cheers,
> Jaden Geller
>
> > On Jun 23, 2017, at 3:52 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:
> >
> > There could be source-breaking implications for such a feature, especially with retroactive conformance. Therefore, I think this could be very tricky and I'd want to be convinced that the benefits are very great to risk such a disturbance. Here, I think the problem is rather mild, and here's why:
> >
> > It is true that, in your example specifically, renaming T to U is the only solution (that I know of, anyway). However, for any "serious" protocol P, there's likely to be a required property of type P.T, or a function that takes an argument of type P.T or returns a value of type P.T. Therefore, implementing that requirement in Bar with a corresponding property/argument/return value of type Bar.T would generally do the trick.
> >
> > Have you got any real-world examples where you're running into this issue?
> >
> > > On Fri, Jun 23, 2017 at 17:03 David Moore via swift-evolution <swift-evolution@swift.org> wrote:
> > > > Hello Swift Evolution,
> > > >
> > > > This may have already been discussed before, but I just came across a bothersome language aspect which reminded me to propose a solution. Currently, if we want to add generics to a protocol the only way to do so is with associated types. I am quite fine with the current approach with respect to those semantics.
> > > >
> > > > There is, however, a weakness that is built in with using associated types. That weakness is the lack of associated type and generic inference. To be more clear about what I mean, take the following as an example.
> > > >
> > > > protocol Foo {
> > > > associatedtype T
> > > > }
> > > >
> > > > The foregoing protocol is quite basic, but uses an associated type with the name “T.” Giving the associated type that name will illustrate the dilemma encountered later on down the pipeline.
> > > >
> > > > struct Bar<T> : Foo {
> > > > // What am I supposed to do? The name is used for both the generic and the type alias Foo needs for conformance.
> > > > typealias T = T // Error!
> > > > }
> > > >
> > > > The above illustrates a situation where we want to connect the generic, which is supposedly named appropriately, and the protocol’s associated type. There is no elegant solution for this at the moment. All I could do is the following.
> > > >
> > > > struct Bar<U> : Foo {
> > > > typealias T = U // Not nearly as readable.
> > > > }
> > > >
> > > > Now, there may be a few ways to go about adding support for generic inference. The compiler as it is already does some awesome inference get when it comes to generics, so why not take it a step further? I propose the introduction of a keyword, or anything else that could work, to specify explicitly what a given type alias declaration would do when it comes to inferencing. Requiring a keyword would ensure source compatibility remains intact, and it would also make the code more readable.
> > > >
> > > > I don’t know if this would be something that people could find useful, but I surely would. The implicit mapping of an associated type and a given generic by their names, would be a natural development.
> > > >
> > > > Let me know if this is just useless, or if could be a potential feature.
> > > >
> > > > Thank you,
> > > > David Moore
> > > > _______________________________________________
> > > > 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


(Xiaodi Wu) #16

There are a few ways in which this issue could be addressed. The first,
and most desirable approach in my opinion, would be full inferencing of a
given associatedtype and a generic. An example of the foregoing would be
the following:

protocol Foo {
    associatedtype ABC
}

struct Bar<ABC> : Foo {
    // Would normally require some sort of workaround to complete the
typealias implementation of the protocol’s associatedtype, but it should be
inferred in this case because there is no explicit typealias statement.
}

The inferencing would indeed take place in the above example. But now
let’s consider the possibility of breaking source compatibility, as in, is
this compatible or not?

struct Bar<ABC>: Foo {
    typealias ABC = ArbitraryType // An inference would not take place
here because there’s nothing to infer. The associated type `ABC` is
explicitly defined as being `ArbitraryType`.
}

The above method shall be referred to as Option #1. It would seem like
Option #1 is source compatible, in addition to solving the original
problem, and potentially introduces some connivence to protocol
conformance. For all existing implementations of associatedtypes and so on,
I don’t think Option #1 affects them at all, unless I’m completely missing
something.

As I mentioned already, this is source breaking for any type Bar that
conforms to Foo where Bar.T is currently distinct from the inferred type of
Foo.T, because the inference would become ambiguous.

In addition, it cannot be right to infer this automatically, as it would be
saying that a typealias named T and an associated type that happens also to
be named T can be assumed to have the same semantics even during
retroactive conformance. This is essentially stringly typing.

More generally, I continue not to understand the motivation. You mentioned
that you wished for there to be a distinction between associated types and
generic type inferences, and this seems to be the opposite of that. Jaden
offered another example, but I am not sure I appreciate why this feature is
desirable or even necessary in that scenario. In Jaden’s example, as in
yours, there is nothing in the protocol itself that demands that
Optional.Wrapped must be the same as OptionalType.Wrapped; this is, rather,
something that is the choice of the author who conforms the type to the
protocol, at the point of conformance. I fail to see why
OptionalType.Wrapped cannot simply have another name, such as WrappedType.

So Option #1 seems like a good candidate.

···

On Tue, Jun 27, 2017 at 16:44 David Moore via swift-evolution < swift-evolution@swift.org> wrote:

Onto Option #2, the idea of using base types to express more explicit
definitions to solve the initial problem. When it comes to using a base
type to correctly disambiguate these types of situations, it may be
familiar to some who like a more concrete implementation, although it
eliminates possible convenience, but still requires knowledge. Options #2
would look something like the following.

protocol Foo {
associatedtype ABC
}

struct Bar<ABC>: Foo {
typealias Foo.ABC = Bar.ABC // Quite explicit and communicates the
solution clearly.
}

Options #2, as you can see above, would also be source compatible because
it would not impose on already defined typealias’ or other implementations.
This could be an opt-in feature. However, I don’t know if it is as nice as
just pure inference, which doesn’t seem too much more difficult than this
would be, but I’m not sure about that.

There is also a third option (referred to as Option #3), which could be
the combination of both Option #1 and Option #2. However, there may be some
syntactically-based issues that can arise in such a situation.

Let me know what everyone thinks about these possible solutions, they are
by no means concretely defined as of this time, but they could be useful.

On Jun 27, 2017, 2:08 PM -0400, Matthew Johnson via swift-evolution < > swift-evolution@swift.org>, wrote:

On Jun 27, 2017, at 12:39 PM, Jaden Geller via swift-evolution < > swift-evolution@swift.org> wrote:

I’ve run into this issue many times in the real world as well. For
example, consider the following protocol:

protocol OptionalType {
    associatedtype Wrapped
}

It is not possible to conform `Optional` to this protocol because its
generic type is already named `Wrapped`. Only when the associated type can
be inferred is conformance possible.

I definitely think we need a solution, but I don’t know what that solution
should be.

I agree. I have run into this as well and have been frustrated by it. It
isn’t clear to me what the best solution is but I’d love to see one that
could make it into a 4.x release.

Cheers,
Jaden Geller

On Jun 23, 2017, at 3:52 PM, Xiaodi Wu via swift-evolution < > swift-evolution@swift.org> wrote:

There could be source-breaking implications for such a feature, especially
with retroactive conformance. Therefore, I think this could be very tricky
and I'd want to be convinced that the benefits are very great to risk such
a disturbance. Here, I think the problem is rather mild, and here's why:

It is true that, in your example specifically, renaming T to U is the only
solution (that I know of, anyway). However, for any "serious" protocol P,
there's likely to be a required property of type P.T, or a function that
takes an argument of type P.T or returns a value of type P.T. Therefore,
implementing that requirement in Bar with a corresponding
property/argument/return value of type Bar.T would generally do the trick.

Have you got any real-world examples where you're running into this issue?

On Fri, Jun 23, 2017 at 17:03 David Moore via swift-evolution < > swift-evolution@swift.org> wrote:

Hello Swift Evolution,

This may have already been discussed before, but I just came across a
bothersome language aspect which reminded me to propose a solution.
Currently, if we want to add generics to a protocol the only way to do so
is with associated types. I am quite fine with the current approach with
respect to those semantics.

There is, however, a weakness that is built in with using associated
types. That weakness is the lack of associated type and generic inference.
To be more clear about what I mean, take the following as an example.

protocol Foo {
    associatedtype T
}

The foregoing protocol is quite basic, but uses an associated type with
the name “T.” Giving the associated type that name will illustrate the
dilemma encountered later on down the pipeline.

struct Bar<T> : Foo {
    // What am I supposed to do? The name is used for both the generic
and the type alias Foo needs for conformance.
    typealias T = T // Error!
}

The above illustrates a situation where we want to connect the generic,
which is supposedly named appropriately, and the protocol’s associated
type. There is no elegant solution for this at the moment. All I could do
is the following.

struct Bar<U> : Foo {
    typealias T = U // Not nearly as readable.
}

Now, there may be a few ways to go about adding support for generic
inference. The compiler as it is already does some awesome inference get
when it comes to generics, so why not take it a step further? I propose the
introduction of a keyword, or anything else that could work, to specify
explicitly what a given type alias declaration would do when it comes to
inferencing. Requiring a keyword would ensure source compatibility remains
intact, and it would also make the code more readable.

I don’t know if this would be something that people could find useful,
but I surely would. The implicit mapping of an associated type and a given
generic by their names, would be a natural development.

Let me know if this is just useless, or if could be a potential feature.

Thank you,
David Moore
_______________________________________________
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

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


(Chris Lattner) #17

Something like this seems like the right approach to me. Swift’s underlying implementation model (for non-@objc protocols) does not require exact name matches and uniqueness. This means that (from an implementation perspective) it would be possible to allow “remapping” of requirements to implementations, even if they have different (or conflicting) names.

This can be useful in some cases, like the one you give above. That said, it would be a power user feature only necessary in specific situations, and thus it makes sense to have super explicit syntax. Given that remapping can apply to any requirement (be it a type, method, property, subscript, …) it may make sense to make it an explicit decl modifier like:

  protocol P {
    var x : Int
    func f() -> Int
  }

  struct S : P {
    var y : Int
    remapped var P.x = y

    func g() -> Int { return 42 }
    remapped var P.f = g
  }

or something.

-Chris

···

On Jun 27, 2017, at 2:26 PM, David Moore via swift-evolution <swift-evolution@swift.org> wrote:

Onto Option #2, the idea of using base types to express more explicit definitions to solve the initial problem. When it comes to using a base type to correctly disambiguate these types of situations, it may be familiar to some who like a more concrete implementation, although it eliminates possible convenience, but still requires knowledge. Options #2 would look something like the following.

protocol Foo {
associatedtype ABC
}

struct Bar<ABC>: Foo {
typealias Foo.ABC = Bar.ABC // Quite explicit and communicates the solution clearly.
}

Options #2, as you can see above, would also be source compatible because it would not impose on already defined typealias’ or other implementations. This could be an opt-in feature. However, I don’t know if it is as nice as just pure inference, which doesn’t seem too much more difficult than this would be, but I’m not sure about that.


(David Moore) #18

The example you presented – whilst utilizing a potential syntactical expression – seems like a step in the right direction. Specifically, I like the addition of a keyword as it introduces a more explicit invocation of the behavior.

Moreover, it does seem only natural to allow the re-mapping to occur for most (if not all) definitions between a protocol and the conforming type. I also agree that this feature would be a more advanced one, which does not need to be exposed for cases where this is not needed.

I would also propose a slight adjustment to the syntax, albeit in a rugged form, to add the type annotation to the right hand side as well. E.g. remapped var P.f = S.g.

If the above were to be respected, then the overall functionality of this could be expanded greatly, but it’d have to be seen how it would affect the implementation. To clarify, if we added the type annotation to the right side too, we may theoretically be able to change the type from the enclosing type to some arbitrary type and its conforming requirement. Now, if this seems a bit too polymorphic the compiler could just emit an error which restricts the type annotation to the enclosing type.

Best,
David Moore

···

On Jul 5, 2017, 1:53 PM -0400, Chris Lattner <clattner@nondot.org>, wrote:

> On Jun 27, 2017, at 2:26 PM, David Moore via swift-evolution <swift-evolution@swift.org> wrote:
>
>
> Onto Option #2, the idea of using base types to express more explicit definitions to solve the initial problem. When it comes to using a base type to correctly disambiguate these types of situations, it may be familiar to some who like a more concrete implementation, although it eliminates possible convenience, but still requires knowledge. Options #2 would look something like the following.
>
> protocol Foo {
> associatedtype ABC
> }
>
> struct Bar<ABC>: Foo {
> typealias Foo.ABC = Bar.ABC // Quite explicit and communicates the solution clearly.
> }
>
> Options #2, as you can see above, would also be source compatible because it would not impose on already defined typealias’ or other implementations. This could be an opt-in feature. However, I don’t know if it is as nice as just pure inference, which doesn’t seem too much more difficult than this would be, but I’m not sure about that.
>

Something like this seems like the right approach to me. Swift’s underlying implementation model (for non-@objc protocols) does not require exact name matches and uniqueness. This means that (from an implementation perspective) it would be possible to allow “remapping” of requirements to implementations, even if they have different (or conflicting) names.

This can be useful in some cases, like the one you give above. That said, it would be a power user feature only necessary in specific situations, and thus it makes sense to have super explicit syntax. Given that remapping can apply to any requirement (be it a type, method, property, subscript, …) it may make sense to make it an explicit decl modifier like:

protocol P {
var x : Int
func f() -> Int
}

struct S : P {
var y : Int
remapped var P.x = y

func g\(\) \-&gt; Int \{ return 42 \}
remapped var P\.f = g

}

or something.

-Chris