I see what you're saying, and I agree that this is more of a half-measure. But the benefit of this approach is that it's pretty trivial to implement, and the language features it introduces could be reimplemented with existentialists when they become available. I think advancing the syntax of the language to improve usability in the near term is worthwhile. If this syntax would not be supported by the existential approach I think that would be a different story.<br><br>Also, I think this could go hand-in-hand with a syntax for types that are protocols with their associated type fulfilled, e.g.<br><br>let grassEater = animal as? AnimalProtocol where Food = Grass<br><br>or:<br><br>let grassEater = animal as? AnimalProtocol<Food: Grass><br><br>These grassEater values could then be used just like any other value.<br><div class="gmail_quote"><div dir="ltr">On Tue, Aug 8, 2017 at 11:14 AM Elviro Rocca <<a href="mailto:retired.hunter.djura@gmail.com">retired.hunter.djura@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word">To my understanding, the following is exactly as it should be:<div><br></div><div>FooStruct<String> as? FooStruct<Any> // Compiles but conversion fails, becomes nil, and that's normal</div><div><br></div><div>The reason for this is that FooStruct<String> is not a subtype of FooStruct<Any> (or just FooStruct), while String is of course a subtype of Any, because generic types are not covariant in Swift, and that's the way it should be for a sound static type system. My comments on this were related to what you wrote about arrays.</div><div><br></div><div>In theory a protocol without associated types could be synthesized for all the non generic properties and methods of a generic type, with the ability of casting to it and possibly from it.</div><div><br></div><div>It's a useful idea, and I'm all for it (I think literally everyone that uses generics and protocols with associated types encountered these kinds of problems at least once), I'm just saying that I'd rather work on generalized existentials which have already been considered by the core team, at least from a theoretical standpoint, have a greater scope and include cases like this. In general I tend to prefer broader, more generic solutions rooted in type theory when dealing with generics and protocols, but that's just me. </div></div><div style="word-wrap:break-word"><div><br></div><div><br></div><div>Elviro</div></div><div style="word-wrap:break-word"><div><div><br></div><div><br><div><blockquote type="cite"><div>Il giorno 08 ago 2017, alle ore 10:44, Logan Shire via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>> ha scritto:</div><br class="m_-4340641306860048956Apple-interchange-newline"><div><div dir="ltr">Thanks for the feedback!<div><br></div><div>Félix, sorry about the confusion between FooStruct and FooProtocol - I'll refer to them as such moving forwards.<br></div><div><br></div><div>David, I don't believe you should be able to cast an [FooStruct<String>] to an [FooStruct<Any>] because those are both valid specifications. If <a href="https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#generalized-existentials" target="_blank">Generalized Existentials</a> are implemented, that would be another story, but that's outside the scope of this proposal. I do believe you should be able to cast [FooStruct<String>] to [FooStruct], and that you should be able to flatMap [FooStruct] into [FooStruct<Any>] with as?, but all of the casts would fail and you would be left with an empty array.</div><div><br></div><div>In regards to the Named protocol, yes, that is the current idiomatic approach to solving this problem (along with making a function unnecessarily generic and then using the generic type as a constraint). I want to avoid jumping through those hoops. We'd essentially be synthesizing the Named protocol with the same name as the non-generic version of the type. I.e. FooStruct<T>: FooStruct</div><div><br></div><div>Félix, I believe the above answers some of your questions, but in regards to protocols with associated types, I'd imagine it would work the same way. If FooProtocol has an associated type T, there would be another protocol, FooProtocol, without the associated type. (behind the scenes its garbled name would be different)</div><div><br></div><div>Also, an aside, it would be nice if protocols could use the generic syntax for their associated type constraints. I.e. "FooProtocol with T = Int" could be expressed as FooProtocol<T: Int>. It feels strange that we have two different syntaxes for essentially the same language construct. At the very least, I want some way to cast a value to a protocol type with an associated value. E.g. "if let grassEater = any as? Animal where Food = Grass"</div><div><br></div><div>Elviro, yes, the generalized existentials would help a lot here, but that's outside the scope of what I'm proposing. In the near term I'd like to be able to use a generic type's non-generic interface, casting to and from it. See the above discussion regarding the Named protocol. Essentially we'd be synthesizing the Named protocol, but where the type's name is the same as the non-generic version of the type name.</div><div><br></div><div>FooStruct<String> as FooStruct // works</div><div>FooStruct as? FooStruct<String> // works</div><div>FooStruct as? FooStruct<Any> // Compiles but conversion fails, becomes nil</div><div>FooStruct<String> as? FooStruct<Any> // Compiles but conversion fails, becomes nil</div><div><div><br></div><div>Let me know if you have any other questions!</div><div><br></div><div>Logan<br><br><div><br><div class="gmail_quote"><div dir="ltr">On Tue, Aug 8, 2017 at 9:43 AM Félix Cloutier <<a href="mailto:felixcloutier@icloud.com" target="_blank">felixcloutier@icloud.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div>I'm going to separate your examples into FooStruct and FooProtocol for clarity.</div><div><br></div><div>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:</div><div><br></div><div></div><blockquote type="cite">func sayHi<T>(to foo: T) where T: FooProtocol {<br> print("hi \(<a href="http://foo.name/" target="_blank">foo.name</a>)")<br>}</blockquote><br><div>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).</div><div><br></div><div>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.</div><div><br></div><div>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.</div><div><br></div><div>But all in all, with my current understanding of the issue, I think that I'm favorable to the idea.</div><div><br></div><div>Félix</div><div><br></div><div><blockquote type="cite"></blockquote></div></div><div style="word-wrap:break-word"><div><blockquote type="cite"><div>Le 7 août 2017 à 19:35, David Sweeris via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>> a écrit :</div><br class="m_-4340641306860048956m_-7626455572048145649m_-643534145729421538Apple-interchange-newline"></blockquote></div></div><div style="word-wrap:break-word"><div><blockquote type="cite"><div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><blockquote type="cite"><div><br class="m_-4340641306860048956m_-7626455572048145649m_-643534145729421538Apple-interchange-newline">On Aug 7, 2017, at 3:00 PM, Logan Shire via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>> wrote:</div><br class="m_-4340641306860048956m_-7626455572048145649m_-643534145729421538Apple-interchange-newline"><div><div style="word-wrap:break-word">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.<div>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.</div><div><br></div><div>For example, if I have a type:</div><div><br></div><div><div style="margin:0px;line-height:normal;font-family:Menlo;color:rgb(255,255,255);background-color:rgb(40,43,53)"><span style="color:rgb(194,52,155)">struct</span> Foo<T> {</div><div style="margin:0px;line-height:normal;font-family:Menlo;color:rgb(255,255,255);background-color:rgb(40,43,53)"> <span style="color:rgb(194,52,155)">let</span> name: <span style="color:rgb(0,175,202)">String</span></div><div style="margin:0px;line-height:normal;font-family:Menlo;color:rgb(255,255,255);background-color:rgb(40,43,53)"> <span style="color:rgb(194,52,155)">let</span> value: <span style="color:rgb(147,201,106)">T</span></div><div style="margin:0px;line-height:normal;font-family:Menlo;color:rgb(255,255,255);background-color:rgb(40,43,53)">}</div></div><div><br></div><div>or:</div><div><br></div><div><div style="margin:0px;line-height:normal;font-family:Menlo;color:rgb(255,255,255);background-color:rgb(40,43,53)"><span style="color:rgb(194,52,155)">protocol</span> Foo {</div><div style="margin:0px;line-height:normal;font-family:Menlo;color:rgb(255,255,255);background-color:rgb(40,43,53)"> <span style="color:rgb(194,52,155)">associatedtype </span><span style="color:rgb(147,201,106)">T</span></div><div style="margin:0px;line-height:normal;font-family:Menlo;color:rgb(255,255,255);background-color:rgb(40,43,53)"> <span style="color:rgb(194,52,155)">var</span> name: <span style="color:rgb(0,175,202)">String </span>{ <span style="color:rgb(194,52,155)">get </span>}</div><div style="margin:0px;line-height:normal;font-family:Menlo;color:rgb(255,255,255);background-color:rgb(40,43,53)"> <span style="color:rgb(194,52,155)">var</span> value: <span style="color:rgb(147,201,106)">T </span>{ <span style="color:rgb(194,52,155)">get </span>}</div><div style="margin:0px;line-height:normal;font-family:Menlo;color:rgb(255,255,255);background-color:rgb(40,43,53)">}</div></div><div><br></div><div>And I want to write a function that only cares about Foo.name, I’d like to be able to:</div><div><br></div><div><div style="margin:0px;line-height:normal;font-family:Menlo;color:rgb(255,255,255);background-color:rgb(40,43,53)"><span style="color:rgb(194,52,155)">func</span> sayHi(to foo: <span style="text-decoration:underline;color:rgb(0,175,202)">F</span><span style="color:rgb(0,175,202)">oo</span>) {</div><div style="margin:0px;line-height:normal;font-family:Menlo;color:rgb(255,255,255);background-color:rgb(40,43,53)"> <span style="color:rgb(0,175,202)">print</span>(<span style="color:rgb(228,67,71)">"hi </span>\<span style="color:rgb(228,67,71)">(</span><a href="http://foo.name/" target="_blank">foo.name</a><span style="color:rgb(228,67,71)">)"</span>)</div><div style="margin:0px;line-height:normal;font-family:Menlo;color:rgb(255,255,255);background-color:rgb(40,43,53)">}</div></div><div><br></div><div>But instead I get the error, “Reference to generic type Foo requires arguments in <…>”</div><div><br></div><div>Also, when you want to have a polymorphic array of generic types, you can’t:</div><div><br></div><div><div style="margin:0px;line-height:normal;font-family:Menlo;color:rgb(255,255,255);background-color:rgb(40,43,53)"><span style="color:rgb(194,52,155)">let</span> foos: [Foo] = [<span style="color:rgb(147,201,106)">Foo</span>(name: <span style="color:rgb(228,67,71)">"Int"</span>, value: <span style="color:rgb(139,132,207)">2</span>), <span style="color:rgb(147,201,106)">Foo</span>(name: <span style="color:rgb(228,67,71)">"Double"</span>, value: <span style="color:rgb(139,132,207)">2.0</span>)]</div></div><div><br></div><div>And if you remove the explicit type coercion, you just get [Any]</div><div><br></div><div><span style="font-family:Menlo;background-color:rgb(40,43,53);color:rgb(194,52,155)">let</span><span style="color:rgb(255,255,255);font-family:Menlo;background-color:rgb(40,43,53)"> foos = [</span><span style="font-family:Menlo;background-color:rgb(40,43,53);color:rgb(147,201,106)">Foo</span><span style="color:rgb(255,255,255);font-family:Menlo;background-color:rgb(40,43,53)">(name: </span><span style="font-family:Menlo;background-color:rgb(40,43,53);color:rgb(228,67,71)">"Int"</span><span style="color:rgb(255,255,255);font-family:Menlo;background-color:rgb(40,43,53)">, value: </span><span style="font-family:Menlo;background-color:rgb(40,43,53);color:rgb(139,132,207)">2</span><span style="color:rgb(255,255,255);font-family:Menlo;background-color:rgb(40,43,53)">), </span><span style="font-family:Menlo;background-color:rgb(40,43,53);color:rgb(147,201,106)">Foo</span><span style="color:rgb(255,255,255);font-family:Menlo;background-color:rgb(40,43,53)">(name: </span><span style="font-family:Menlo;background-color:rgb(40,43,53);color:rgb(228,67,71)">"Double"</span><span style="color:rgb(255,255,255);font-family:Menlo;background-color:rgb(40,43,53)">, value: </span><span style="font-family:Menlo;background-color:rgb(40,43,53);color:rgb(139,132,207)">2.0</span><span style="color:rgb(255,255,255);font-family:Menlo;background-color:rgb(40,43,53)">)]</span></div><div><br></div><div>I wish that could be inferred to be [Foo].</div></div></div></blockquote><div><br></div><div>What happens if you try to say "foos: [Foo<Any>] = ..."? </div><div><br></div><div><br></div><br><blockquote type="cite"><div><div style="word-wrap:break-word"><div>I’d like to propose being able to use the non-generic interface of a type normally. </div><div>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.</div><div>It could be a parameter in a function, a variable, or even the generic type of another type (like a Dictionary<String, Foo>)</div><div><br></div><div>The only restriction is that if you want to call or access, directly or indirectly, a function or member that requires the generic type,</div><div>the generic type would have to be known at that point.</div><div><br></div><div>Foo<T> should be able to be implicitly casted to Foo wherever you want, and Foo could be cast to Foo<T> conditionally.</div><div>Initializers would still obviously have to know the generic type, but given the above example, you should be able to:</div><div><br></div><div><div style="margin:0px;line-height:normal;font-family:Menlo;color:rgb(255,255,255);background-color:rgb(40,43,53)"><span style="color:rgb(194,52,155)">let</span> names = <span style="color:rgb(147,201,106)">foos</span>.<span style="color:rgb(0,175,202)">map</span> { $0.<span style="color:rgb(147,201,106)">name</span> }</div></div><div><br></div><div>However, you could not do the following:</div><div><br></div><div><div style="margin:0px;line-height:normal;font-family:Menlo;color:rgb(255,255,255);background-color:rgb(40,43,53)"><span style="color:rgb(194,52,155)">let</span><span class="m_-4340641306860048956m_-7626455572048145649m_-643534145729421538Apple-converted-space"> </span>foos = [<span style="color:rgb(147,201,106)">Foo</span>]()</div></div><div><br></div><div>Because the initializer would need to know the generic type in order to allocate the memory.</div><div><br></div><div>Let me know what you think!</div></div></div></blockquote></div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><br></div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px">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.</div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><br></div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px">+1, either way, though.</div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><br></div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px">- Dave Sweeris</div></div></blockquote></div></div><div style="word-wrap:break-word"><div><blockquote type="cite"><div><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important">_______________________________________________</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important">swift-evolution mailing list</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><a href="mailto:swift-evolution@swift.org" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px" target="_blank">swift-evolution@swift.org</a><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a></div></blockquote></div><br></div></blockquote></div></div></div></div></div>
_______________________________________________<br>swift-evolution mailing list<br><a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br></div></blockquote></div><br></div></div></div></blockquote></div>