Make a Functions Able to Handle Different Classes as Parameters - swift

I'm trying to pass different classes, with the same properties, to the same function. How do I cast them for use with this function?
Below is a simple example to highlight what I'm trying to achieve.
class A {
var height:Int = 10
}
class B {
var height:Int = 20
}
class C {
static func grow(class:AnyObject) {
class.height + 5
}
}
C.grow(A)
C.grow(B)
The two final calls should yield 15 and 25, but without casting the AnyObject back to A or B, an error like the following is generated: "AnyObject has no member named".
How do I accomplish something like this?

Swift reflection API enables you to read values but not modify them. So if that's enough for you, you may use a method similar to the following which takes an object and the label of the member you want to access:
func getValue<T>(object: AnyObject, memberLabel: String) -> T? {
let mirror = Mirror(reflecting: object)
for member in mirror.children {
if let _ = member.label where member.label == memberLabel,
let value = member.value as? T {
return value
}
}
return nil
}
But if you want to modify the values, you have to define a protocol and make the classes conform to it:
protocol HasHeight {
var height: Int { get set }
}
extension HasHeight {
mutating func grow() {
self.height += 5
}
}
class A : HasHeight {
var height = 10
}
class B : HasHeight {
var height = 20
}
var a = A()
print(a.height)
a.grow()
print(a.height)
var b = B()
print(b.height)
b.grow()
print(b.height)
Here I defined grow() as a protocol extension so that it is available on every class/struct that conforms to the HasHeight protocol.
The results are:
10
15
20
25
You may define it elsewhere, but the call will have to be changed to include an & reference:
func grow<T: HasHeight>(inout sized: T) {
sized.height += 5
}
grow(&b)

Looks like a good case for a protocol! Define one with a height property, have A and B both implement that protocol, and then have the grow method accept the protocol as its parameter.

Related

Swift Generics and Protocols

Given the below, this will throw a compile time error about the protocol not being able to adhere to itself and only struct/enum can adhere to the protocol. This seems to defeat the purpose of being able to use protocols in generics. I'm trying to understand why this doesn't work, but if I remove the generic and just put the protocol where 'Z' is everything is fine. It seems antithetical to what protocols and generics should be allowed for.
**Edit for question clarity: I need to take a type of Any that can be cast to a dictionary of [String:MyProtocol] and pass it into the method printEm. printEm must use the generic as it will be instantiating instances of the class Z.
protocol MyProtocol {
init()
var whoAmI:String { get }
}
func genericPassing(unknownThing:Any) {
let knownThing = unknownThing as? [String:MyProtocol]
if(knownThing != nil){
self.printEm(knownThing)
}
}
func printEm<Z:MyProtocol>(theThings:[String:Z]) {
let zCollection:[Z] = []
for thing in theThings {
print(thing.whoAmI)
zCollection.append(Z())
}
}
**Edited printEm to illustrate why generic is needed.
** Edit for more complex code. The two primary requirements are the use of a generic to call Z() and the ability to take an Any and somehow type check it and/or cast it so that it can be used in a genericized method.
private func mergeUpdates<Z:RemoteDataSyncable>(source:inout Z, updates:[WritableKeyPath<Z, Any>:Any]) throws {
for key in updates.keys {
let value = updates[key]!
let valueDict = value as? [String:[WritableKeyPath<RemoteDataSyncable, Any>:Any]]
if(valueDict != nil) {
var currentValueArray = source[keyPath: key] as? [RemoteDataSyncable]
if(currentValueArray != nil) {
self.mergeUpdates(source: &currentValueArray!, updates: valueDict!)
}
else {
throw SyncError.TypeError
}
}
else {
source[keyPath: key] = value
}
}
}
private func mergeUpdates<Z:RemoteDataSyncable>(source:inout [Z], updates:[String:[WritableKeyPath<Z,Any>:Any]]) {
for key in updates.keys {
var currentObject = source.first { syncable -> Bool in
return syncable.identifier == key
}
if(currentObject != nil) {
try! self.mergeUpdates(source: &currentObject!, updates: updates[key]!)
}
else {
var newSyncable = Z()
try! self.mergeUpdates(source: &newSyncable, updates: updates[key]!)
source.append(newSyncable)
}
}
}
This is a perfect example of why protocols do not conform to themselves. In your code Z is MyProtocol, so Z() is MyProtocol(). How would that work? What type is it? How big is it? You then can't put them into a [Z], since they might be different types.
You mean to pass arbitrary MyProtocols and call init on the type of each element:
func printEm(theThings:[String: MyProtocol]) {
var zCollection:[MyProtocol] = []
for thing in theThings.values {
print(thing.whoAmI)
zCollection.append(type(of: thing).init())
}
}
When I suggested using closures, this is the kind of thing I mean. This Updater can accept arbitrary ReferenceWritableKeyPaths, and when you pass it Any update value, it'll assign it to every key path that can accept it. That's kind of useless, but shows the technique. (Keep in mind that the updater is retaining the object, so that may be a problem that you need to address.)
class Updater {
private(set) var updaters: [(Any) -> ()] = []
func add<Root, Value>(keyPath: ReferenceWritableKeyPath<Root, Value>, on root: Root) {
updaters.append { value in
if let value = value as? Value {
root[keyPath: keyPath] = value
}
}
}
func updateAll(with value: Any) {
for updater in updaters {
updater(value)
}
}
}
class Client {
var updateMe: Int = 0
}
let client = Client()
let updater = Updater()
updater.add(keyPath: \.updateMe, on: client)
updater.updateAll(with: 3)
client.updateMe // 3
The key lesson in this code is that the generic types on the add are erased (hidden) by the (Any) -> () closure at compile-time. And the runtime as? check is done inside that closure, where the types are all known.

Swift 4 way to fake existentials with protocols and `Self`

There are hundreds of solutions to fake existentials in Swift with protocols and Self, but they mostly refer to Swift 2 and the bright future that Swift 3 might bring...
Now Swift 4 is out, with nice additions for Generics. But I couldn't find any suggestions how to fit that into the missing existentials problem.
Any Ideas how to solve this the Swift 4 way?
Example:
import UIKit
protocol Bla {
func compare(other: Self)
}
extension CGFloat : Bla {
func compare(other: CGFloat) {
print("Extended CGFloat")
}
}
extension UIEdgeInsets : Bla {
func compare(other: UIEdgeInsets) {
print("Extended UIEdgeInsets")
}
}
/* Possible, but what if we want to CGFloat _and_ UIEdgeInsets inside here?
Well, that would _not_ work! */
class Possible<T: Bla> {
var array: [T]!
}
/* This is open to everything...
And therefore fails to compile, no dynamic type info at runtime I guess. */
class Fail {
var array: [Bla]!
}
// Works, but I don't need that.
let list = Possible<CGFloat>()
// I need that:
let list = Fail()
let f: CGFloat = 1.23
let edge = UIEdgeInsets()
list.array.append(f)
list.array.append(edge)
Fundamentally, it can't be done. If you could have:
class Fail {
var array: [Bla]!
}
You could then try to write code like this:
func compareAll(foo: Fail)
{
for x in foo.array
{
x.compare(other: y)
}
}
What type is y? The protocol says it has to be the same type as the object adopting the protocol but you don't know the type of x until runtime. There is no way to write that code with y being both a UIEdgeInsets and a CGFloat at the same time.
I think you could make it work by removing the dependency on Self by making compare generic. Your protocol would look like this:
protocol Bla {
func compare<T: Bla>(other: T)
}
Implementations of compare would have to test the type of other and cast to the right type.
extension CGFloat: Bla
{
func compare<T: Bla>(other: T)
{
if let casted = other as? CGFloat
{
// do whatever
}
}
}
I think this approach is better than using type erasure (see Daniel Hall's answer) for a couple of reasons:
There's no overhead of having to wrap everything in a wrapper object or the indirection of compare.
The compare function can work when other is an arbitrary type, not just the same type of self if it makes sense e.g.
func compare<T: Bla>(other: T)
{
if let casted = other as? CGFloat
{
// do whatever
}
else if let casted = other as? UIEdgeInsets
{
// Do something else
}
}
Of course, if you are simply given the protocol and you can't change it, type erasure is your only option.
This is typically handled with a type eraser, for example:
struct AnyBla: Bla {
private let compareClosure: (Any) -> ()
func compare(other: AnyBla) {
compareClosure(other)
}
init<T: Bla>(_ bla: T) {
compareClosure = {
if let other = $0 as? T {
bla.compare(other: other)
} else {
print("Can't compare type \(type(of: bla)) with \(type(of: $0))")
}
}
}
}
Then you would change your array to any array of the type eraser, i.e.
class Fail {
var array: [AnyBla]!
}
Then you can accomplish what you want to do like this:
let list = Fail()
let f: CGFloat = 1.23
let edge = UIEdgeInsets()
list.array.append(AnyBla(f))
list.array.append(AnyBla(edge))
Swift 4 didn't make any generics changes that address this issue. For the full roadmap, see the Generics Manifesto. That said, the protocol you're describing is equivalent to Equatable, and so would have all the same problems. There is no current roadmap to create what you're describing. The closest is discussed at the very end of the Manifesto, in the section called "Opening existentials."
As you've described the problem, it isn't clear how it would be useful, so I suspect your actual problem is different. You should go back to your actual program and consider what its real requirements are. For example, if your real requirement is "an array of CGFloat or UIEdgeInsets" that is absolutely buildable in Swift. "An array" translates to [T], and "OR" translates to enum (Swift's "sum type" in type theory parlance). So what you mean is:
enum Element {
case scalar(CGFloat)
case insets(UIEdgeInsets)
}
let list: [Element]
That is completely different than "an array of things that can be compared to themselves." If, on the other hand, you really mean "an array of value-like things," then that also is pretty easy to build in Swift with NSValue (and its subclass, NSNumber):
class Things {
var array: [NSValue] = []
func append(_ value: CGFloat) {
array.append(NSNumber(value: Double(value)))
}
func append(_ insets: UIEdgeInsets) {
array.append(NSValue(uiEdgeInsets: insets))
}
}
let list = Things()
let f: CGFloat = 1.23
let edge = UIEdgeInsets()
list.append(f)
list.append(edge)
list.array[0] == list.array[0] // true
list.array[0] == list.array[1] // false

Declare a Swift protocol which has a property return value CollectionType<Int>?

Is something like
protocol A {
var intCollection: CollectionType<Int> { get }
}
or
protocol A {
typealias T: CollectionType where T.Generator.Element == Int
var intCollection: T
}
possible in Swift 2.1?
Update for Swift 4
Swift 4 now support this feature! read more in here
Not as a nested protocol, but it's fairly straightforward using the type erasers (the "Any" structs).
protocol A {
var intCollection: AnyRandomAccessCollection<Int> { get }
}
This is actually often quite convenient for return values because the caller usually doesn't care so much about the actual type. You just have to throw a return AnyRandomAccessCollection(resultArray) at the end of your function and it all just works. Lots of stdlib now returns Any erasers. For the return value problem, it's almost always the way I recommend. It has the nice side effect of making A concrete, so it's much easier to work with.
If you want to keep the CollectionType, then you need to restrict it at the point that you create a function that needs it. For example:
protocol A {
typealias IntCollection: CollectionType
var intCollection: IntCollection { get }
}
extension A where IntCollection.Generator.Element == Int {
func sum() -> Int {
return intCollection.reduce(0, combine: +)
}
}
This isn't ideal, since it means you can have A with the wrong kind of collection type. They just won't have a sum method. You also will find yourself repeating that "where IntCollection.Generator.Element == Int" in a surprising number of places.
In my experience, it is seldom worth this effort, and you quickly come back to Arrays (which are the dominant CollectionType anyway). But when you need it, these are the two major approaches. That's the best we have today.
You can't do this upright as in your question, and there exists several thread here on SO on the subject of using protocols as type definitions, with content that itself contains Self or associated type requirements (result: this is not allowed). See e.g. the link provided by Christik, or thread Error using associated types and generics.
Now, for you example above, you could do the following workaround, however, perhaps mimicing the behaviour you're looking for
protocol A {
typealias MyCollectionType
typealias MyElementType
func getMyCollection() -> MyCollectionType
func printMyCollectionType()
func largestValue() -> MyElementType?
}
struct B<U: Comparable, T: CollectionType where T.Generator.Element == U>: A {
typealias MyCollectionType = T
typealias MyElementType = U
var myCollection : MyCollectionType
init(coll: MyCollectionType) {
myCollection = coll
}
func getMyCollection() -> MyCollectionType {
return myCollection
}
func printMyCollectionType() {
print(myCollection.dynamicType)
}
func largestValue() -> MyElementType? {
guard var largestSoFar = myCollection.first else {
return nil
}
for item in myCollection {
if item > largestSoFar {
largestSoFar = item
}
}
return largestSoFar
}
}
So you can implement blueprints for your generic collection types in you protocol A, and implement these blueprints in the "interface type" B, which also contain the actual collection as a member property. I have taken the largestValue() method above from here.
Example usage:
/* Examples */
var myArr = B<Int, Array<Int>>(coll: [1, 2, 3])
var mySet = B<Int, Set<Int>>(coll: [10, 20, 30])
var myRange = B<Int, Range<Int>>(coll: 5...10)
var myStrArr = B<String, Array<String>>(coll: ["a", "c", "b"])
myArr.printMyCollectionType() // Array<Int>
mySet.printMyCollectionType() // Set<Int>
myRange.printMyCollectionType() // Range<Int>
myStrArr.printMyCollectionType() // Array<String>
/* generic T type constrained to protocol 'A' */
func printLargestValue<T: A>(coll: T) {
print(coll.largestValue() ?? "Empty collection")
}
printLargestValue(myArr) // 3
printLargestValue(mySet) // 30
printLargestValue(myRange) // 10
printLargestValue(myStrArr) // c

Protocols and composition on Swift

I am trying to learn more about protocols and got stuck without understanding what is going on on the following piece of code. Mostly seeking some light and direction for good articles and pieces of explanation basically.
In one of the examples from Apple's Library protocols are doing a bit more than making sure the classes conform to it.
They are allowing objects from one class to access methods within other classes without using the traditional class inheritance definition.
This line of code let generator: RandomNumberGenerator on the Dice class is allowing the var d6 that is of type Dice to access a function func random() -> Double that is outside of Dice scope and inside LinearCongruentialGenerator scope and is using the RandomNumberGenerator to make this bridge.
Also allowing to do the following call d6.generator.random() when again .ramdom() is not on Dices scope.
protocol RandomNumberGenerator {
func random() -> Double
}
class LinearCongruentialGenerator: RandomNumberGenerator {
var lastRandom = 42.0
let m = 139968.0
let a = 3877.0
let c = 29573.0
func random() -> Double {
lastRandom = ((lastRandom * a + c) % m)
return lastRandom/m
}
}
class Dice {
let sides: Int
let generator: RandomNumberGenerator
init(sides: Int, generator: RandomNumberGenerator) {
println(generator.random())
self.sides = sides
self.generator = generator
}
func roll() -> Int {
return Int(generator.random() * Double(sides)) + 1
}
}
var d6 = Dice(sides: 6, generator: LinearCongruentialGenerator())
Update to question
Thanks for the answers! By doing some research I think I just touched composition. So I wrote the code bellow to exemplify composition a bit better, without using protocols or delegates. Just pure composition. Please let me know if I got it right as it may help other people trying to understand composition.
class A {
var a1: String
init (valueToA: String){
self.a1 = valueToA
}
func aFunc1() -> A {
return self
}
}
class B {
var b1: A
init (valueToB: A ) {
self.b1 = valueToB
}
func bFunc1(){
println("I am bFunc and I am calling aFunc \(b1.aFunc1())")
}
}
var myA = A(valueToA: "Initiated myA with this string")
//myA.aFunc1()
var myB = B(valueToB: myA)
myB.b1 = A(valueToA: "a value to B")
myB.b1.aFunc1()
The same code but now with protocols
protocol myProtocol {
func protocolFunc(value: String) -> String
}
class A: myProtocol {
var a1: String
init (valueToA: String){
self.a1 = valueToA
}
func aFunc1() -> A {
return self
}
func protocolFunc(value: String) -> String {
return value
}
}
class B {
var b1: A
var b2: myProtocol
init (valueToB1: A, valueToB2: myProtocol ) {
self.b1 = valueToB1
self.b2 = valueToB2
}
func bFunc1(){
println("I am bFunc and I am calling aFunc \(b1.aFunc1())")
}
func callProtocolFuncOnA (value: String) {
b1.protocolFunc(value)
}
}
var myA1 = A(valueToA: "my A 1 created")
var myA2 = A(valueToA: "my A 2 created")
var myB = B(valueToB1: myA1, valueToB2: A(valueToA: "my A 3 created"))
myB.callProtocolFuncOnA("calling other function")
As #DevAndArtist says in his comment it allows encapsulation (abstraction) when a type of RandomNumberGenerator is passed in the initializer of the Dice class and so only that part of your implementation is visible to you.
In my humble opinion it could be better if the constant generator was not visible outside the Dice class scope as you say in your question, for example making his access modifier private, but remember that in your example all is set in the same swift file and this implies that the private access modifier isn't like the other programming languages like C#, Java, etc.
Even doing private you can access d6.generator.random() in your call because it exist in the same Swift file, the only way you can hide the property if you create a new Swift file for the Dice class and then this call when the property is private of course :
var d6 = Dice(sides: 6, generator: LinearCongruentialGenerator())
println(d6.generator.random())
gave you the following error:
'Dice' does not have a member named 'generator'
And you can hide the property outside of its scope. It's only a point of view.
I hope this help you.

How do I initialize a property that depends on another property, when I don't have access to self yet?

I have two properties in my class. See this terrible example:
var length
var doubleLength
How do I initialize doubleLength based on length?
init() {
self.length = ...
self.doubleLength = self.length * 2
super.init()
}
I get an error that I can't access self before I call super.init(). Well I need to set all my variables before I can even call super.init() so what am I supposed to do?
if self.doubleLength is always supposed to be twice self.length (in this example) have you considered just using a computed property?
class MyClass: MySuperClass {
var length: Double
var doubleLength: Double {
return self.length * 2
}
init(len: Double) {
self.length = len
super.init()
}
}
You can temporarily delay the initialization of doubleLength an implicitly unwrapped optional, which will allow to temporarily assign a value to nil and assign it at a later time.
class Something: UICollectionViewLayout {
var doubleLength: Int! = nil
var length: Int {
return 50
}
init() {
super.init()
doubleLength = length * 2
}
}
Anyway, in this specific case I think it would be nicer to make doubleLength a computed property, since it can be always be computed from the value of length. Your class will be like
class Something: UICollectionViewLayout {
var doubleLength: Int {
return length * 2
}
var length: Int {
return 50
}
}
Thanks for your full reproduction, which is:
import UIKit
class Something: UICollectionViewLayout {
var doubleLength: Int
var length: Int {
return 50
}
init() {
doubleLength = length * 2
super.init()
}
}
From this we can see that you're using a getter to return your property. I think this is what's causing the problem. For example, if you just do this:
import UIKit
class Something: UICollectionViewLayout {
var doubleLength: Int
// Simple variable, no code.
var length = 50
init() {
doubleLength = length * 2
super.init()
}
}
...then that works fine.
I believe this is because the Swift compiler is trying to prevent you from doing anything that might mean you use the base class's methods, properties or variables before it's been initialised. I know you're technically not, in your example, but consider how hard it is to trace back and see what's being done from your initialiser. For example, if you were to do:
var length: Int {
// Where "width" is a made-up property of UICollectionViewLayout
return width * 3
}
...then your code would be run from your initialiser and use a property of UICollectionViewLayout before its own init had been called, therefore making it possibly invalid.
So my best guess is that this is the Swift compiler making a blanket ban on calling out to any code outside the subclass initialiser before the super is initialised.
You get exactly the same error if you do this, for example:
class Something: UICollectionViewLayout {
func foo() {
// Do nothing
}
init() {
foo() // error: 'self' used before super.init call
super.init()
}
}
The place I remember this being explained is the "Intermediate Swift" video from WWDC 2014, from slide 191, about 20 minutes in, but I'm guessing it's somewhere in the book, too...
A property that depends on another is bad practice. Just like when you design a database, you avoid calculated fields, when you design classes, you also avoid calculated fields. Instead of having a doubleLength property, you should instead have a getDoubleLength method that returns the length * 2.