
Limitations of protocols in Swift - panic
http://inessential.com/2015/12/10/im_harping_on_this
======
Manishearth
I'm not a Swift person, so I might be wrong, but this seems like a case where
composition over inheritance is preferred. Protocols in Swift (and traits in
Rust) are not supposed to be used to emulate classical inheritance; though
they can be. Enums/ADTs/sum types/whatever you call them are what you're
supposed to use in such cases.

~~~
fauigerzigerk
I disagree. This is the classic case for protocols. Look what he says:

 _" I’m using a protocol for the Account type. There are classes that conform
to the Account protocol: TwitterAccount, AppNetAccount, LinkedInAccount,
etc."_

The important bit is the "etc." at the end. The types of accounts he wants to
support is open ended. He also mentions a plug-in API. You can't have third
parties come in and extend some algebraic data type.

If this is not a case for protocols then there is no such case at all and
protocols should be removed from the language.

~~~
captaincrowbar
To me this looks like exactly the sort of situation where classical OO
inheritance is the right answer. All of those things are kinds of Account and
should have a common base class.

~~~
Manishearth
Classical OO inheritance is the right answer in a language that supports it,
though. There may be equally ergonomic ways of doing it in languages with
ADTs.

(Which may or may not be the case here, depending on extensibility)

------
jcizzle
This isn't a limitation of Swift, this is someone trying to write Objective-C
in Swift.

Let's say he gets what he wants - a distinct collection of instances that
fulfill the 'Account' contract, but are different types. The approach so far
is that to fulfill 'Account' by providing an accountID. That accountID is what
indicates if two 'Account's are equal. What if a Twitter account and Hacker
News account have the same id? According to this protocol, they are equal.

The error message he is seeing about Self requirements is telling him this.
That error message doesn't exist because Swift is having a hard time
understanding the code, it exists because Swift understands that his code is
wrong.

~~~
nathanvanfleet
You're missing the point of what he's saying with a pretty dismissive
statement. "Swift doesn't do that" is not a strong argument.

He specifically goes through why using protocols like that are a useful and
powerful tool. He's making an argument about its usefulness and the ease of
implementing it.

It is a really useful tool! It lets you show the commonalities and mask and
private methods in classes. I would say that it would be a loss to not have
this.

As for the "this might accidentally be seen as equal to something that is a
different class" should not be a problem. In objective C isEqual implemented
in a standard way is able to differentiate different classes from each other
pretty much from the beginning of the method.

~~~
jcizzle
Not saying Swift doesn't do that, saying he's doing it wrong. Protocols can
still be interfaces (what he and you are describing), there is no loss. Two
types that simply implement a similar protocol are by definition not
necessarily equatable. The 'standard' way that Objective-C implements isEqual:
is _on a base class_ , which is a totally possible implementation in Swift as
well.

~~~
nathanvanfleet
That's the point he's making. He doesn't want a base class.

If you aren't lucky enough to have them be of the base class you have to
create an empty template superclass just to satisfy the compiler. Objective-c
has a better solution and things can dovetail without being in the same class.

"Doing it wrong" implies that Swift is just inherently better without making a
real argument about why that would be the case. And the OP is actually making
a pretty convincing argument that it isn't.

Swift is awesome at doing things better than obj-c and it really does reduce a
lot of template code. But maybe not in this particular instance (right now).

~~~
jcizzle
He can't solve this problem without using a base class, so he wants to go back
to Objective-C _where he will use a base class_? Objective-C does not have a
better solution - it has the same solution here. The only difference is that
ObjC will let you do what he is trying to do where the actual result is
incorrect. That doesn't make Swift inherently better, it means he is wrong. OP
is not making a convincing argument, and this isn't a point about Swift vs.
ObjC. OP is just complaining because they don't understand what it is they are
doing.

~~~
coldtea
I don't think you understand what the parent is telling you at all.

It's clear from what they wrote that both the parent and the author of TFA
know all that you described. The problem is not that they don't know these
things or that they're "doing it wrong", it's that they disagree that the way
Swift does is it's the better way, or in PL terms, the most expressive way.

> _Let 's say he gets what he wants - a distinct collection of instances that
> fulfill the 'Account' contract, but are different types. The approach so far
> is that to fulfill 'Account' by providing an accountID. That accountID is
> what indicates if two 'Account's are equal. What if a Twitter account and
> Hacker News account have the same id? According to this protocol, they are
> equal._

So? There's nothing wrong with that. If that's how he defines equality and not
at the class level, that's what he should get. He should still be able to use
a set with his definition of "equal" (which he could trivially change anyway).

------
Veedrac
I don't know Swift, but the problem seems to be that you can't do

    
    
        extension ListItem: Hashable
    

where ListItem is a protocol. That's a little irksome, sure, but why not just
do

    
    
        struct ListItemBox {
            var item: ListItem
        }
    
        func ==(lhs: ListItemBox, rhs: ListItemBox) -> Bool {
            return lhs.item.id == rhs.item.id
        }
    
        extension ListItemBox: Hashable {
            var hashValue: Int {
                return item.id
            }
        }
    
        var stuff: Set<ListItemBox>;
    

Of course, you should be very careful about cross-type equality here. But
that's no easier with any other model either.

~~~
seanalltogether
I think it can be reduced into simpler terms in fact. In swift you simply
can't do

    
    
      var stuff:Set  
      var stuff:Set<Hashable>  
      var stuff:Set<MyProtocol>
    

Sets don't allow for mixed base types, and that's what a protocol would allow.
All objects in a set must contain a similar base type. This is actually true
in obj-c as well where everything in a set had to derive from NSObject.

------
seanalltogether
One option available to him is to make Feeds conform to something he can
guarantee will be hashable, specifically NSObjectProtocol. The would force all
Feed objects to inherit from NSObject and hashability will come along for the
ride, but I understand his desire to make things lighter.

------
cellularmitosis
Two things which might be useful to him:

Rob napier's article on type erasure:
[http://robnapier.net/erasure](http://robnapier.net/erasure)

Alexis Gallagher's talk on PATs and generic constraints:
[https://youtu.be/XWoNjiSPqI8](https://youtu.be/XWoNjiSPqI8)

