Swift protocol using another protocol causes error - swift

I'm working in Swift 4.
I want to define a Problem.
A Problem consists of a Question and an Answer.
The Question might be any of: String, Int, [Int], Image, [Image] or some new Type not defined or could be some combination of the above.
The Answer might also be any of the above but a given Question can have an Answer of a different type.
(e.g. question = (Image, "What type of animal is this?), answer = ("A Cat") )
So I thought protocols would be the way to go:
protocol Posable {
var pose: String { get }
}
protocol Answerable: Hashable {
var answer: String { get }
}
protocol Puzzle {
var problem: Posable { get }
var solution: Answerable { get }
}
I made Answerable Hashable because I want to be able to compare Answers and create sets of Answers.
But I get on the solution: Answerable line:
'Protocol 'Answerable' can only be used as a generic constraint because it has Self or associated type requirements.
I understand why that is but...
Can anyone make any suggestions about how to implement this so that I don't run into that problem?
I'm keen to implement with protocols if possible, partly so that I learn about them.

I would solve it with generics :
import UIKit
struct Posable<T> {
var pose: T
}
struct Answerable<T> {
var answer: T
}
extension Answerable: Equatable where T: Equatable {
static func ==(lhs: Answerable<T>, rhs: Answerable<T>) -> Bool {
return lhs.answer == rhs.answer
}
}
extension Answerable: Hashable where T: Hashable {
var hashValue: Int {
return answer.hashValue
}
}
struct Puzzle<T, U> {
var problem: Posable<T>
var solution: Answerable<U>
}
let image = UIImage() // Image of a cat
let pose = Posable<(UIImage, String)>(pose: (image, "What type of animal is this?"))
let solution = Answerable<String>(answer: "A cat")
let myPuzzle = Puzzle<(UIImage, String), String>(problem: pose, solution: solution)
Generics allow you to make very reusable code! Here you can use any class as a question or as an anwser.
With Swift type inherence : you also get to simplify the initialization :
let image = UIImage() // Image of a cat
let pose = Posable(pose: (image, "What type of animal is this?"))
let solution = Answerable(answer: "A cat")
let myPuzzle = Puzzle(problem: pose, solution: solution)

I'm not sure but you can remove Hashable from Answerable.
protocol Posable {
var pose: String { get }
}
protocol Answerable {
var answer: String { get }
}
protocol Puzzle {
var problem: Posable? { get }
func getSolution<T: Hashable & Answerable>() -> T
}

Related

Structures vs classes in swift

I was reading about type erasure in swift. After reading an article, I decided to write a simple implementation of "chain of responsibility" pattern and came up with this solution:
protocol Responsibility {
associatedtype ParameterType
associatedtype ResultType
func process(_ data: ParameterType) -> ResultType?
}
struct AnyResponsibility<ParameterType, ResultType>: Responsibility {
private let processData: (ParameterType) -> ResultType?
init<R: Responsibility>(_ responsibility: R) where R.ParameterType == ParameterType, R.ResultType == ResultType {
processData = responsibility.process
}
func process(_ data: ParameterType) -> ResultType? {
processData(data)
}
}
protocol ResponsibilityChain {
associatedtype ParameterType
associatedtype ResultType
var responsibilities: [AnyResponsibility<ParameterType, ResultType>] { get }
}
struct AnyResponsibilityChain<ParameterType, ResultType>: ResponsibilityChain {
init<Chain: ResponsibilityChain>(_ chain: Chain) where Chain.ParameterType == ParameterType, Chain.ResultType == ResultType {
responsibilities = chain.responsibilities
}
let responsibilities: [AnyResponsibility<ParameterType, ResultType>]
}
struct MyResponsibility: Responsibility {
func process(_ data: Int) -> Int? {
data + 1
}
}
struct MyChain: ResponsibilityChain {
init(_ responsibilities: [AnyResponsibility<Int, Int>]) {
self.responsibilities = responsibilities
}
let responsibilities: [AnyResponsibility<Int, Int>]
}
However, in example code from this article: https://www.donnywals.com/understanding-type-erasure-in-swift/ they seem to favor classes over structures. Is there any good reason why it would be better to use classes in my code?
I know that classes are reference types but I always favor let over var so it shouldn't matter in this case. Am I right? I have also read this article: https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html but I didn't found any solution to my problem.
I'm coming to swift from C++ background and we tend to use classes when the object has some logic, and use structures when the object only holds some properties. Is it a case in swift?

Swift, Protocols and Generics in Genetic Algorithm

I am trying to switch from Java to Swift and improve my programming skills in this language.
However, I have some difficulties understanding how generics works in Swift after a study of:
https://docs.swift.org/swift-book/LanguageGuide/Generics.html
I have started to write a genetic algorithm by writing some protocols.
protocol Point : Equatable {
var identifier: String { get }
var x: Double { get }
var y: Double { get }
func distance<P : Point>(to point: P) -> Double
}
protocol Individual {
associatedtype P : Point
var fitness: Double { get }
var chromosomes: [P] { get }
}
and now I want to make a struct which conforms to the Individual protocol.
The only try that compiles is
struct Route : Individual {
typealias P = City;
var fitness: Double { 0.0 }
var chromosomes: [City]
}
However, I want to make Route as much as generic, therefore I don't want to tell that it uses City as implementation of Point. I want that Route knows that it works on array of objects which conforms to Point protocol.
I'd appreciate your help.
Thank you in advance.
First of all, I'd suggest adding a Self requirement on the distance(to:) method. Self just tells the compiler that the paremeter is the same type as the conforming type.
protocol Point : Equatable {
var identifier: String { get }
var x: Double { get }
var y: Double { get }
func distance(to point: Self) -> Double
}
So, in your City struct point must also be of type City.
struct City: Point {
var identifier: String
var x: Double
var y: Double
func distance(to point: City) -> Double {
return .zero
}
}
You can make your Route struct more flexible by adding a generic parameter that also satisfies the associated type requirement imposed by the Individual protocol.
struct Route<P: Point>: Individual {
var fitness: Double { 0.0 }
var chromosomes: [P]
}
To instantiate a Route:
var cityRoute = Route<City>(chromosomes: [])
You can create an array of class that implements a specific protocol, so for example in this case you will have:
struct Route: Individual {
typealias P = City;
var fitness: Double { 0.0 }
var chromosomes: [Point]
}
and you can call all the protocol methods.

Why can't we use protocol `Encodable` as a type in the func?

I'm trying to get data by encode model which conforms to Encodable protocol. But it's failed to invoke func encode like code below:
// MARK: - Demo2
class TestClass2: NSObject, Encodable {
var x = 1
var y = 2
}
var dataSource2: Encodable?
dataSource2 = TestClass2()
// error: `Cannot invoke 'encode' with an argument list of type '(Encodable)'`
let _ = try JSONEncoder().encode(dataSource2!)
//func encode<T>(_ value: T) throws -> Data where T : Encodable
But in another demo, it works well, why?
// MARK: - Demo1
protocol TestProtocol {
func test()
}
class TestClass1: NSObject, TestProtocol {
func test() {
print("1")
}
var x = 1
var y = 2
}
var dataSource1: TestProtocol?
dataSource1 = TestClass1()
func logItem(_ value: TestProtocol) {
value.test()
}
logItem(dataSource1!)
Solution 1.
Try this code, which extend encodable
extension Encodable {
func toJSONData() -> Data? { try? JSONEncoder().encode(self) }
}
Solution 2.
To avoid polluting Apple-provided protocols with extensions
protocol MyEncodable: Encodable {
func toJSONData() -> Data?
}
extension MyEncodable {
func toJSONData() -> Data?{ try? JSONEncoder().encode(self) }
}
Use
var dataSource2: Encodable?
dataSource2 = TestClass2()
let data = dataSource2?.toJSONData()
You can't pass a protocol but you can use generics to require a class that conforms to one:
func printJSON<T: Encodable>(_ data: T) {
if let json = try? JSONEncoder().encode(data) {
if let str = String(data: json, encoding: .utf8) {
print(str)
}
}
}
// Now this should work
var dataSource2 = TestClass2()
printJSON(dataSource2!)
There are a number of approaches to solving this problem.
#SPatel solution of extending Encodable is one possibility. However, I personally try to avoid polluting Apple-provided protocols with extensions.
If I am reading between the lines, it appears what you are wanting is to pass any construct that conforms to Encodable to a function/method in some other struct/class.
Let's take an example of what I think you are trying to achieve:
struct Transform {
static func toJson(encodable: Encodable) throws -> Data {
return try JSONEncoder().encode(encodable)
}
}
However, Xcode will complain:
Protocol type 'Encodable' cannot conform to 'Encodable' because only concrete types can conform to protocols
A Swift-ier solution is to use a constrained generic on the function:
struct Transform {
static func toJson<EncodableType: Encodable>(encodable: EncodableType) throws -> Data {
return try JSONEncoder().encode(encodable)
}
}
Now the compiler can infer the type that conforms to Encodable, and we can call the function as intended:
let dataSource = TestClass2()
let jsonData = try? Transform.toJson(encodable: dataSource)
Your 2 examples are different.
JSONEncoder().encode() expects a concrete class which conforms to the procotol Encodable. The reference dataSource2 holds a protocol and not a concrete class.
logItem on the other hands, only takes a protocol as input, and NO concrete class which conforms to the protocol. This is the difference between your examples and why your second case is working and the first case does not.
With your current setup, it will not work. You need to pass in a concrete class to the JSONEncoder.
As long as TestClass2 is Encodable you can use following code. encode should know what to encode. It refers to class properties to do that. Encodable itself doesn't contain any properties.
JSONEncoder().encode(dataSource2 as! TestClass2)
Could it be you're just looking for this ?
func blah<T>(_ thing: T) where T: Codable {
do {
let data = try JSONEncoder().encode(thing)
.. do something with data
} catch {
print("severe problem in blah, couldn't encode")
}
}

The method in the protocol extension is never get called, plus, an error in the book

At page 261 ~ 262 of the book "Swift ApprenticeBeginning programming with Swift 2.2" there is a sample code about protocol extension is shown as follow
the value gamesPlayed is defined in the protocol TeamRecord, the protocol extension and the structure BaseballRecord
protocol TeamRecord {
var wins: Int { get }
var losses: Int { get }
var gamesPlayed: Int { get }
}
extension TeamRecord {
// gamesPlay#1
var gamesPlayed: Int {
return (wins + losses)
}
}
struct BaseballRecord: TeamRecord{
var wins: Int
var losses: Int
// gamesPlay#2
let gamesPlayed: Int = 162
}
let team1: TeamRecord = BaseballRecord(wins: 10, losses: 5)
let team2: BaseballRecord = BaseballRecord(wins: 10, losses: 5)
team1.gamesPlayed//The book claimed it will invoke "gamesPlay#1" (15)
team2.gamesPlayed//The book claimed it will invoke "gamesPlay#2" (162)
Problem: According to the description of the book, the gamesPlayed called by team1 invokes the implementation in the protocol extension (gamesPlay#1); while the gamesPlayed called by team2 invokes the implementation (gamesPlay#2) in the BaseballRecord structure.
But the Xcode 7.3 playground told me a different story, both team1.gamesPlayed and team2.gamesPlayed invokes the implementation in the structure rather than the protocol extension.
Question I might be misled by the sloppy writing of this part of the book! If not, please correct me. (the picture here is captured from the book)
Thanks a lot for your kind help and time
Extra Staff: Dear friends. In case you found this question and also bothered by the same issue, here comes the simple self-contained code I wrote after I learned from the kind helpers. Just copy and paste it into your Xcode playground. Hope this will help you a bit.
protocol MyProtocol {
func hardCasting()
}
extension MyProtocol {
func foo() {
print("Printing from the protocol extension")
}
func fooDefaul() {
print("Not implemented in type, I'm prented from the protocol extension")
}
func hardCasting() {
print("You shouldn't see this!!! YOU SHALL NOT PASS!")
}
}
struct MyType: MyProtocol {
func foo() {
print("Printing from the type")
}
func hardCasting() {
print("No matter what! I get only printed out by type!")
}
}
let lumi: MyProtocol = MyType()
lumi.foo()
lumi.fooDefaul()
let lumiProtocol: MyProtocol = MyType()
let lumiType: MyType = MyType()
lumiProtocol.hardCasting()
lumiType.hardCasting()
You are correct, this is an error in the book. Concrete implementations are always selected before a protocol extension if the method is declared in the protocol definition itself.
However, if the method is added by protocol extension, is not declared in the protocol definition, and is also implemented in a concrete type, you can get the extension's implementation by casting the concrete type to the protocol.
In other words, if the sample code had included this:
protocol TeamRecord {
var wins: Int { get }
var losses: Int { get }
}
instead of this:
protocol TeamRecord {
var wins: Int { get }
var losses: Int { get }
var gamesPlayed: Int { get }
}
then the comments in the book would be correct.
There's a very thorough exploration of this here:
https://nomothetis.svbtle.com/the-ghost-of-swift-bugs-future

How to define initializers in a protocol extension?

protocol Car {
var wheels : Int { get set}
init(wheels: Int)
}
extension Car {
init(wheels: Int) {
self.wheels = wheels
}
}
on self.wheels = wheels i get the error
Error: variable 'self' passed by reference before being initialized
How can I define the initializer in the protocol extension?
As you can see this doesn't work under these circumstances because when compiling, one has to make sure that all properties are initialized before using the struct/enum/class.
You can make another initializer a requirement so the compiler knows that all properties are initialized:
protocol Car {
var wheels : Int { get set }
// make another initializer
// (which you probably don't want to provide a default implementation)
// a protocol requirement. Care about recursive initializer calls :)
init()
init(wheels: Int)
}
extension Car {
// now you can provide a default implementation
init(wheels: Int) {
self.init()
self.wheels = wheels
}
}
// example usage
// mark as final
final class HoverCar: Car {
var wheels = 0
init() {}
}
let drivableHoverCar = HoverCar(wheels: 4)
drivableHoverCar.wheels // 4
As of Xcode 7.3 beta 1 it works with structs as expected but not with classes since if they are not final the init(wheels: Int) in the protocol is a required init and it can be overridden therefore it cannot be added through an extension. Workaround (as the complier suggests): Make the class final.
Another workaround (in depth; without final class)
To work with classes without making them final you can also drop the init(wheels: Int) requirement in the protocol. It seems that it behaves no different than before but consider this code:
protocol Car {
var wheels : Int { get set }
init()
// there is no init(wheels: Int)
}
extension Car {
init(wheels: Int) {
self.init()
print("Extension")
self.wheels = wheels
}
}
class HoverCar: Car {
var wheels = 0
required init() {}
init(wheels: Int) {
print("HoverCar")
self.wheels = wheels
}
}
// prints "HoverCar"
let drivableHoverCar = HoverCar(wheels: 4)
func makeNewCarFromCar<T: Car>(car: T) -> T {
return T(wheels: car.wheels)
}
// prints "Extension"
makeNewCarFromCar(drivableHoverCar)
So if you make a Car from a generic context where the type on which you call init is only to be known as Car the extension initializer is called even though an initializer is defined in HoverCar. This only occurs because there is no init(wheels: Int) requirement in the protocol.
If you add it you have the former problem with declaring the class as final but now it prints two times "HoverCar". Either way the second problem probably never occurs so it might be a better solution.
Sidenote: If I have made some mistakes (code, language, grammar,...) you're welcome to correct me :)
My understanding is that this isn't possible, because the protocol extension can't know which properties the conforming class or struct has - and therefore cannot guarantee they are correctly initialized.
If there are ways to get around this, I'm very interested to know! :)
#Qbyte is correct.
In addition, you can take a look at my Configurable
In that I have Initable protocol
public protocol Initable {
// To make init in protocol extension work
init()
}
public extension Initable {
public init(#noescape block: Self -> Void) {
self.init()
block(self)
}
}
Then in order to conform to it
extension Robot: Initable { }
I have 2 ways, using final or implement init
final class Robot {
var name: String?
var cute = false
}
class Robot {
var name: String?
var cute = false
required init() {
}
}
May not be the same but in my case instead of using init I used a static func to return the object of the class.
protocol Serializable {
static func object(fromJSON json:JSON) -> AnyObject?
}
class User {
let name:String
init(name:String) {
self.name = name
}
}
extension User:Serializable {
static func object(fromJSON json:JSON) -> AnyObject? {
guard let name = json["name"] else {
return nil
}
return User(name:name)
}
}
Then to create the object I do something like:
let user = User.object(fromJSON:json) as? User
I know its not the best thing ever but its the best solution I could find to not couple business model with the data layer.
NOTE: I'm lazy and I coded everything directly in the comment so if something doesn't work let me know.