> On 8. Aug 2017, at 04:35, David Sweeris via swift-evolution > <swift-evolution@swift.org> wrote: > >> >> 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>] = ..."? >
Foo<Int> and Foo<Any> are very different. Otherwise, you could take a Foo<Int>, cast it to a Foo<Any> and set a String as its value. I think what he means are partial generics, e.g: Foo<_>. > > >> 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 swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution