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 <[email protected]> wrote: >> >> On Fri, Jun 23, 2017 at 8:29 PM, David Moore via swift-evolution >> <[email protected]> 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 <[email protected]>, wrote: >>> Yes, examples will be helpful. >>> >>> >>>> On Fri, Jun 23, 2017 at 19:28 David Moore via swift-evolution >>>> <[email protected]> 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 <[email protected]> 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 >>>>>> <[email protected]> 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 >>>>>> [email protected] >>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution >>>> _______________________________________________ >>>> swift-evolution mailing list >>>> [email protected] >>>> https://lists.swift.org/mailman/listinfo/swift-evolution >> >> _______________________________________________ >> swift-evolution mailing list >> [email protected] >> https://lists.swift.org/mailman/listinfo/swift-evolution >
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
