Writing all protocol types with Any<> (was [Review] SE-0095)


(Jordan Rose) #1

That’s a good “slippery slope” argument, definitely worth bringing up. I think my counterpoint is that I’m not convinced that writing something generic over non-final classes is a common case. People use subclasses for dynamic polymorphism a lot more than they do static, i.e. the static type of a class doesn’t really give you any more information than the dynamic type. Additionally:

- You have to see the allocation to do optimization anyway,
- The compiler can optimize equally well whether you use a generic function or plain old dynamic dispatch.
- A class reference is already as efficient to pass around as it can be, whereas existentials and generics are more expensive than their concrete types.

But it’s definitely something to consider.

Jordan

···

On Jun 2, 2016, at 23:24, Thorsten Seitz <tseitz42@icloud.com> wrote:

Am 02. Juni 2016 um 05:15 schrieb Jordan Rose via swift-evolution <swift-evolution@swift.org>:

On Jun 1, 2016, at 14:18, Austin Zheng <austinzheng@gmail.com <mailto:austinzheng@gmail.com>> wrote:

I'd also like to express my support for the proposal to delineate generic and existential syntax: all existentials must be written with Any<...>; generic type constraints cannot use it. I hope this will make it clear to people learning and using the language that, despite their superficial similarities, they are actually two different concepts.

This is definitely getting off-topic for this particular review, but I’ve come to agree with you. I can only speak for myself, but back when we were implementing protocols in Swift it felt great to eliminate the wedge between ’NSTableView *’ and ‘id <NSTableViewDelegate>’. But then we started using protocols for many more things in Swift, and it turns out that the simple use case of “I have a protocol-typed property” isn’t really the one worth optimizing for anymore. When they’re arguments, you more often than not might want to use them generically, and you should at least be thinking about that when you define a function.

Where we are today, the protocol-typed value is the obvious choice, and then you move to generics when the compiler tells you no. Having the choice be between these two:

func foo<T: SignedInteger>(value: T)
func foo(value: Any<SignedInteger>)

makes it a little more likely that someone will stop and think about picking the first.

But doesn't this apply not only for protocols but for non-final classes, too? These are existentials as well, i.e. C ::= ∃ t : C . t

As a result we would have to write all protocols and all non-final class types with `Any<>`:

func foo(table: Any<NSTableView>)