I'm going to separate your examples into FooStruct and FooProtocol for clarity.

I agree that generics tend to propagate virally and I remember that at some 
point I wanted type erasure, though I don't remember for what exactly. The 
solution for `sayHi`, right now, is to make that one generic too:

> func sayHi<T>(to foo: T) where T: FooProtocol {
>     print("hi \(foo.name)")
> }

The "let foos: [FooStruct] = [FooStruct(name: "Int", value: 2), FooStruct(name: 
"Double", value: 2.0)]" part can't work for structs because arrays require each 
element to have the same size (but it could work for classes).

Even then, you couldn't infer the type to [FooClass<Any>] because 
contravariance isn't permissible in that situation: doing so would allow you to 
assign any Any to a FooClass's value.

Another problem that this would have to solve is that once you lose the 
associatedtype that came with the protocol, there is nothing you can do to 
recover it; you currently can't express "FooProtocol with T = Int" as a type 
that you can cast to, so you would only be able to pass the instance to 
functions that don't have constraints on T.

But all in all, with my current understanding of the issue, I think that I'm 
favorable to the idea.


> Le 7 août 2017 à 19:35, David Sweeris via swift-evolution 
> <swift-evolution@swift.org> a écrit :
>> On Aug 7, 2017, at 3:00 PM, Logan Shire via swift-evolution 
>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>> One of my longstanding frustrations with generic types and protocols has 
>> been how hard it is to work with them when their type is unspecified.
>> Often I find myself wishing that I could write a function that takes a 
>> generic type or protocol as a parameter, but doesn’t care what its generic 
>> type is.
>> For example, if I have a type:
>> struct Foo<T> {
>>     let name: String
>>     let value: T
>> }
>> or:
>> protocol Foo {
>>     associatedtype T
>>     var name: String { get }
>>     var value: T { get }
>> }
>> And I want to write a function that only cares about Foo.name, I’d like to 
>> be able to:
>> func sayHi(to foo: Foo) {
>>     print("hi \(foo.name)")
>> }
>> But instead I get the error, “Reference to generic type Foo requires 
>> arguments in <…>”
>> Also, when you want to have a polymorphic array of generic types, you can’t:
>> let foos: [Foo] = [Foo(name: "Int", value: 2), Foo(name: "Double", value: 
>> 2.0)]
>> And if you remove the explicit type coercion, you just get [Any]
>> let foos = [Foo(name: "Int", value: 2), Foo(name: "Double", value: 2.0)]
>> I wish that could be inferred to be [Foo].
> What happens if you try to say "foos: [Foo<Any>] = ..."? 
>> I’d like to propose being able to use the non-generic interface of a type 
>> normally. 
>> I.e. if you have a type Foo<T>, it is implicitly of type Foo as well. The 
>> type Foo could be used like any other type.
>> It could be a parameter in a function, a variable, or even the generic type 
>> of another type (like a Dictionary<String, Foo>)
>> The only restriction is that if you want to call or access, directly or 
>> indirectly, a function or member that requires the generic type,
>> the generic type would have to be known at that point.
>> Foo<T> should be able to be implicitly casted to Foo wherever you want, and 
>> Foo could be cast to Foo<T> conditionally.
>> Initializers would still obviously have to know the generic type, but given 
>> the above example, you should be able to:
>> let names = foos.map { $0.name }
>> However, you could not do the following:
>> let foos = [Foo]()
>> Because the initializer would need to know the generic type in order to 
>> allocate the memory.
>> Let me know what you think!
> The idiomatic solution would be to create a `Named` protocol with a `var 
> name: String {get}` property, and write your function like `func sayHi(to 
> foo:Named) {...}`. However, this `Named`protocol is really pretty trivial -- 
> its purpose is simply to "degenericify" a generic type, not to provide any 
> semantic meaning. Perhaps an analogy could be drawn between such "trivial 
> protocols" and how we sometimes view tuples as "trivial structs"? Dunno, 
> maybe I'm just trying to turn two trees into a forest, but this kinda smells 
> like it might be part of a bigger issue, and if it is I'd rather tackle that 
> and then see if we still need to address anything here.
> +1, either way, though.
> - Dave Sweeris
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
> https://lists.swift.org/mailman/listinfo/swift-evolution 
> <https://lists.swift.org/mailman/listinfo/swift-evolution>
swift-evolution mailing list

Reply via email to