Search code examples
swiftgenericsmixins

Function with multiple classes that have a mixin


The Mixin

I have a mixin that prints the assigns the class name as a String to an instance variable.

import Foundation

protocol Recyclable {
    static var name: String { get }
}

extension Recyclable {
    static var name: String {
        return String(describing: Self.self)
    }
}

There are two classes that implement the mixin:

class One: NSObject, Recyclable { }
class Two: NSObject, Recyclable { }

So if I want to print the class name, I can just

One.self.name // "One"

This works perfectly. Now let's get deeper.

Generic function to print multiple given classes

Putting this into a function to print the name of all given classes. It needs to be a generic, since it can accept any class that conforms to the Recyclable protocol.

func printAllNames<T: NSObject>(_ things: T.Type...) where T: Recyclable {
    for thing in things {
        print(thing.name)
    }
}

If I use this for one class only, it works as expected.

printAllNames(One.self) // "One"

But when used with more than one, it errors out

printAllNames(One.self, Two.self)

Playground execution failed: error: GenericMixins.playground:20:1: error: generic parameter 'T' could not be inferred printAllNames(One.self, Two.self)


Any hints on what might be happening?

Playground: https://www.dropbox.com/sh/q0b5b3oo0luj471/AABSG2QEOIj_SBsvtv7cEv-Ka?dl=0


Solution

  • I ended up figuring it out. The right approach is to make function accept anything, and then check if what was accepted conforms to the protocol.

    The function should be

    func printAllNames(_ things: AnyObject...) {
        for thing in things {
            if let klass = thing.self as? Recyclable.Type {
                print(klass.name)
            }
        }
    }
    

    And then it works as expected

    printAllNames(One.self, Two.self)
    

    One

    Two


    Updated playground: https://www.dropbox.com/sh/9sjboo3lfu83662/AAC9CKn_dU_wrihCvKUfujQ7a?dl=0