Limitations of protocols in Swift
inessential.com
inessential.com
For example I've been working on a Json library that stores everything in an enum (ADT):
public enum JsValue {
case JsString(String)
case JsNumber(Double)
case JsObject([String: JsValue])
case JsArray([JsValue])
case JsBoolean(Bool)
case JsNull
}Trait objects in Rust let you emulate inheritance. The issue I was talking about is that folks from inheritance-heavy languages use this as the de facto design pattern, and then stuff doesn't work so well, because you're not supposed to use inheritance so much (the languages aren't designed with this in mind). The correct option is to use enums and composition over inheritance wherever possible.
Saying use composition over inheritance "wherever possible" can lead to some cargo culting on its own. It is always possible to use composition over inheritance, but it isn't always wise.
Pretty much what I meant, when I said "wherever possible" I meant "wherever possible with decent code", sorry about the confusion.
"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.
That's a bit harsh. You forget that protocols are useful for generics too.
But yes, if they want it to be extensible, protocols would be the way to go.
Looking deeper into the issue, it seems like this isn't really an issue with protocols, just an issue with the design of Hashable or Equatable (either allow Equatable to work with protocol objects, or move the Equatable dependency of Hashable to a different kind of Equatable).
This sounds like a nitpick, but it's the difference between language and API design, and the latter is often easier to evolve. It also means that this can be fixed by a ProtocolHashSet<T> library which does hashing differently without touching the compiler/stdlib at all.
(Which may or may not be the case here, depending on extensibility)
enum Car {
case Red
case Blue
}
extension Car {
func hello() {
print("hello")
}
}
let x = Car.Blue
x.hello()
https://developer.apple.com/library/ios/documentation/Swift/...edit: although you can't add a new case to the enum.
That's the point. We all know you can add impls or extensions.
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.
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.
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).
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).
Might try to write one tomorrow, really.
Maybe that's the desired behaviour?
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. 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.Rob napier's article on type erasure: http://robnapier.net/erasure
Alexis Gallagher's talk on PATs and generic constraints: https://youtu.be/XWoNjiSPqI8