Associated protocol in Swift - swift

I'm trying to abstract views that are configured from a view model. I've been using associated types so far:
public protocol ViewModelProtocol: Equatable {}
public protocol ModeledView: class {
/// The type of the view model
associatedtype ViewModel: ViewModelProtocol
var viewModel: ViewModel? { get }
/// Sets the view model. A nil value describes a default state.
func set(newViewModel: ViewModel?)
}
Which I can use like:
struct MyViewModel: ViewModelProtocol {
let foo: String
static public func == (lhs: MyViewModel, rhs: MyViewModel) -> Bool {
return lhs.foo == rhs.foo
}
}
class MyView: UIView, ModeledView {
typealias ViewModel = MyViewModel
private(set) var viewModel: MyViewModel?
public func set(newViewModel: MyViewModel?) {
print(newViewModel?.foo)
}
}
However I'd like to specify a protocol for my view models, and not a concretized type. The reason is that one struct / class could comply to several such view model protocols. I don't want to either convert this object to another type just to pass it to the view, or have the view have an associated type with more requirements than it needs. So I think I'd like to do something like:
protocol MyViewModelProtocol: ViewModelProtocol {
var foo: String { get }
}
class MyView: UIView, ModeledView {
typealias ViewModel = MyViewModelProtocol
private(set) var viewModel: MyViewModelProtocol?
public func set(newViewModel: MyViewModelProtocol?) {
print(newViewModel?.foo)
}
}
struct DataModel: MyViewModelProtocol {
let foo: String
let bar: String
static public func == (lhs: MyViewModel, rhs: MyViewModel) -> Bool {
return lhs.foo == rhs.foo && lhs.bar == rhs.bar
}
}
let dataModel = DataModel(foo: "foo", bar: "bar")
let view = MyView()
view.set(newViewModel: dataModel)
This doesn't work. The compiler says that MyView doesn't conform to the ModeledView protocol, and hints that
Possibly intended match 'MyView.ViewModel' (aka 'MyViewModelProtocol') does not conform to 'ViewModelProtocol'
I don't really get what's bothering the compiler as MyViewModelProtocol is defined as extending ViewModelProtocol

MyViewModelProtocol is defined as extending ViewModelProtocol
Correct. MyViewModelProtocol extends ViewModelProtocol. It doesn't conform to ViewModelProtocol. This is a classic case of "protocols do not conform to themselves." Your associated type requires that ViewModel be a concrete type that conforms to ViewModelProtocol, and MyViewModelProtocol is not a concrete type and it does not conform to anything (protocols do not conform to protocols).
The way to attack this problem is to start with the calling code, and then construct protocols that support what you want the calling code to look like. In the code you've given, the correct solution is to get rid of ModeledView entirely. It isn't doing anything; nothing relies on it, and it doesn't provide any extensions. I assume in your "real" code, something does rely on it. That's the key piece of code to focus on. The best way to achieve that is to write a few concrete examples of the kinds of conforming types you'd like to exist. (If you have trouble writing several concrete implementations, then reconsider whether there's anything to abstract.)
Just to elaborate a bit more why this won't work in your specific case (it won't work in more general cases either, but your case layers additional restrictions that are important). You've required that types that conform to ViewModelProtocol also conform to Equatable. That means they must implement:
static public func == (lhs: Self, rhs: Self) -> Bool {
This does not mean that some type conforming to ViewModelProtocol is Equatable to some other type conforming to ViewModelProtocol. It means Self, the specific, concrete type implementing the protocol. ViewModelProtocol is not itself Equatable. If it were, which code above would you expect dataModel == myViewModel to call? Would it check bar or not? Remember, == is just a function. Swift doesn't know that you're asking "are these equal." It can't inject things like "if they're different concrete types they're not equal." That's something the function itself has to do. And so Swift needs to know which function to call.
Making this possible in Swift will be a major addition to the language. It's been discussed quite a lot (see the link I posted in the earlier comments), but it's at least several releases away.
If you remove the Equatable requirement, it still won't work today, but the language change required is much smaller (and may come sooner).

Related

When to switch from struct to class in swift?

I am thinking on this for hours:
Lets say you have a generic game. The game can have players and an methode that sets a score. This can be done by using a protocol:
protocol Game {
var players: [Player] {get set}
func setScore (for player: Player, value: Int)
func sendSomeMessage(message: String)
}
i can now create a struct confirming to the protocol "Game"
struct raiseGame: Game {
var players: [Player]()
func setScore (for player: Player, value: Int) {
player.score += value
}
func sendSomeMessage(message: String) {
players.forEach { player in
//send the message to each player
}
}
}
But then i have, lets say, another struct conforming to Game. But in this time the score should be decreased. All other things stay the same. Now i have to write all the code for the func sendSomeMessage again. (There could be many more functions which stays the same).
The question is now: Should i switch to a class, write a base class and inherit from it, or is there a way to provide somekind of default implementations for functions in protocols, so i don't need to write them every time again, when confirming to a protocol?
is there a way to provide somekind of default implementations for functions in protocols, so i don't need to write them every time again, when confirming to a protocol?
There is indeed a way to provide default method implementations for protocol-conforming types:
protocol MyProtocol {
func myMethodRequirement()
}
extension MyProtocol {
func myMethodRequirement() {
// Default implementation.
}
}
struct Foo: MyProtocol {
func myMethodRequirement() {
// Foo-specific implementation.
}
}
struct Bar: MyProtocol {
/* Inherits default implementation instead. */
}
In your case, giving sendSomeMessage(message:) a default implementation would look like:
extension Game {
func sendSomeMessage(message: String) {
// Default implementation here.
}
}
Any type conforming to Game could either implement sendSomeMessage(message:) itself (similar to override-ing a method in a class), or use the default implementation without doing any additional work.
For more information, you can see the "Providing Default Implementations" section on protocols of the The Swift Programming Language guide.
To answer the title of your question, then, given that it is possible to do this for structs:
A class may be useful over a struct if you have an inheritance hierarchy multiple levels deep, which may be more complicated to express using protocol conformances
A class may be useful over a struct when you need reference semantics — see:
Structures and Enumerations are Value Types and
Classes are Reference Types
In your specific case, it doesn't immediately appear that either of these apply, but with more information, it might become obvious whether switching would be beneficial or not.

What's the point of conforming to an empty protocol in Swift

I'm just working on a codebase where the most classes conform to an empty protocol. Is there any point of doing so? Actually conforming that protocol does nothing.
Edit as reaction to #vacawama's helpful comment : the protocol is only used once
import Foundation
protocol myUrlRequestConfig {}
extension myUrlRequest: myUrlRequestConfig {
public static func configGetAppConfig() -> URLRequest {
let request = ....
return request
}
}
An empty protocol can be useful if you want to create an easy way to add static functions or variables to several different classes. Of course, this only makes sense if the static functionality is the same for all classes conforming to the protocol.
Here is an example: I have a protocol sizeable. Every class that conforms to Sizeable is extended with the static variable stride and size.
protocol Sizeable { }
extension Sizeable {
static var size: Int {
return MemoryLayout<Self>.size
}
static var stride: Int {
return MemoryLayout<Self>.stride
}
}
class Foo: Sizeable {}
class Baa: Sizeable {}
Foo.size
Baa.size
Our app has three perfectly legitimate uses for an empty protocol:
The protocol has an extension with method definitions. The implementation in the extension is automatically injected into any type that adopts the protocol.
The protocol has other protocols that adopt it. This allows multiple protocols to be unified under a single head.
The protocol marks the adopter as wanting some other type to behave in a certain way. Code can always is whether an object is ThisEmptyProtocol and if it is, can behave differently than if it isn't.

Can one Swift typealias be constrained to another in a protocol definition? If not, how else can I achieve something like component registration?

I am writing a small inversion of control container for my own little framework in swift (mainly so I can learn more) and I have stumbled across a problem - well, several problems of which this is just the latest.
I had hoped that swift would be flexible enough for me to port the core patterns of Castle.Core in C#. My first disappointment was in the weak reflection capabilities provided by Apple, which led me to do this ugliness...
public protocol ISupportInjection {
}
public protocol IConstructorArguments {
func toArgumentsDictionary() -> [String:AnyObject?]
}
public protocol ISupportConstructorInjection: ISupportInjection {
init(parameters:IConstructorArguments)
}
...the idea being that someday (soon) I could deal with it and remove any reference to these constraints in my services/components.
Now I want to write IIocRegistration with two typealias: one for the TService and the other for the TComponent, ideally where TService is a protocol and TComponent is a concrete struct or class that implements TService:
public protocol IIocRegistration {
typealias TService: Any
typealias TComponent: TService, ISupportConstructorInjection
}
But it seems that TComponent: TService is totally invalid according to the compiler, which says:
Inheritance from non-protocol, non-class type '`Self`.TService'
So I am wondering how to make a typealias derive another typealias if it possible.
First of all what typealias do inside a swift protocol is not to define a type alias. The keyword typealias inside swift protocol is used to define associated type about which you can check out the swift programming book.
Back to your situation the possible solution I can come up with is move the typealias outside protocol like such
public typealias TService = Any
public struct component: TService, ISupportConstructorInjection {
public init(parameters: IConstructorArguments) {
//
}
}
public typealias TComponent = component
public protocol IIocRegistration {
var service: TService {get set}
var component: TComponent {get set}
}

Statically typed properties in Swift protocols

I'm trying to use Protocol-Oriented Pgrogramming for model layer in my application.
I've started with defining two protocols:
protocol ParseConvertible {
func toParseObject() -> PFObject?
}
protocol HealthKitInitializable {
init?(sample: HKSample)
}
And after implementing first model which conforms to both I've noticed that another model will be basically similar so I wanted to create protocol inheritance with new one:
protocol BasicModel: HealthKitInitializable, ParseConvertible {
var value: AnyObject { get set }
}
A you can see this protocol has one additional thing which is value but I want this value to be type independent... Right now I have models which use Double but who knows what may show up in future. If I leave this with AnyObject I'm sentenced to casting everything I want to use it and if I declare it as Double there's no sense in calling this BasicModel but rather BasicDoubleModel or similar.
Do you have some hints how to achieve this? Or maybe I'm trying to solve this the wrong way?
You probably want to define a protocol with an "associated type",
this is roughly similar to generic types.
From "Associated Types" in the Swift book:
When defining a protocol, it is sometimes useful to declare one or
more associated types as part of the protocol’s definition. An
associated type gives a placeholder name (or alias) to a type that is
used as part of the protocol. The actual type to use for that
associated type is not specified until the protocol is adopted.
Associated types are specified with the typealias keyword.
In your case:
protocol BasicModel: HealthKitInitializable, ParseConvertible {
typealias ValueType
var value: ValueType { get set }
}
Then classes with different types for the value property can
conform to the protocol:
class A : BasicModel {
var value : Int
func toParseObject() -> PFObject? { ... }
required init?(sample: HKSample) { ... }
}
class B : BasicModel {
var value : Double
func toParseObject() -> PFObject? { ... }
required init?(sample: HKSample) { ... }
}
For Swift 2.2/Xcode 7.3 and later, replace typealias in the
protocol definition by associatedtype.

Why use class only protocols in Swift?

Can anyone please explain class only protocols to me in Swift. I understand what protocols are and why we use them. I also understand that its recommended to use class only protocols when we use reference type objects in it and want to limit the protocol conformation to classes only. However, I can't find any good answer to support that recommendation. Why is it recommended? What is the drawbacks of using normal protocols in that case.
One use case:
You have a "delegate" protocol and someone wants to have a weak property of that protocol type. weak can only be used on reference types; therefore, the protocol must be class-only.
Another use case used to be to extend reference types to adopt protocols. You can't extend AnyObject itself (to inherit from another protocol, or for any other reason) but you have any reference types you want adopt a protocol inherited from AnyObject.
For example, having class equality based on unique identity is often a perfectly fine solution, so you could adopt EquatableObject:
public protocol EquatableObject: AnyObject, Equatable { }
public extension EquatableObject {
static func == (class0: Self, class1: Self) -> Bool {
class0 === class1
}
}
But now, we have protocol extension constraints (using where clauses), so instead of extending AnyObject, we can extend the protocol, and use AnyObject as a constraint. It looks backwards but operates identically, and removes the need for our own protocol. 🥳
public extension Equatable where Self: AnyObject {
static func == (class0: Self, class1: Self) -> Bool {
class0 === class1
}
}