What you need to do is use style erasure, such as AnyHashable in the Swift standard library.
You can not:
var a: [Hashable] = [5, "Yo"] // error: protocol 'Hashable' can only be used as a generic constraint because it has Self or associated type requirements
What you need to do is use the type of the erasable type AnyHashable :
var a: [AnyHashable] = [AnyHashable(5), AnyHashable("Yo")] a[0].hashValue
So, your solution was to first split the protocol into smaller parts and promote Equatable in Hashable (to reuse AnyHashable )
protocol Conditionable { var condition: Condition? { get set } } protocol Executable { func execute() -> SKAction } protocol Commandable: Hashable, Executable, Conditionable {}
Then create an AnyCommandable structure, for example:
struct AnyCommandable: Commandable, Equatable { var exeBase: Executable var condBase: Conditionable var eqBase: AnyHashable init<T: Commandable>(_ commandable: T) where T : Equatable { self.condBase = commandable self.exeBase = commandable self.eqBase = AnyHashable(commandable) } var condition: Condition? { get { return condBase.condition } set { condBase.condition = condition } } var hashValue: Int { return eqBase.hashValue } func execute() -> SKAction { return exeBase.execute() } public static func ==(lhs: AnyCommandable, rhs: AnyCommandable) -> Bool { return lhs.eqBase == rhs.eqBase } }
And then you can use it as follows:
var a = FunctionCommand() a.commands = [AnyCommandable(MoveCommand()), AnyCommandable(FunctionCommand())]
And you can easily access the properties of commands , because AnyCommandable implements Commandable
a.commands[0].condition
You need to remember that now add Hashable and Equatable to all your teams. I used these implementations for testing:
struct MoveCommand: Commandable { var movingVector: CGVector! var condition: Condition? func execute() -> SKAction { return SKAction() } var hashValue: Int { return Int(movingVector.dx) * Int(movingVector.dy) } public static func ==(lhs: MoveCommand, rhs: MoveCommand) -> Bool { return lhs.movingVector == rhs.movingVector } } struct FunctionCommand: Commandable { var commands = [AnyCommandable]() var condition: Condition? func execute() -> SKAction { return SKAction.group(commands.map { $0.execute() }) } var hashValue: Int { return commands.count } public static func ==(lhs: FunctionCommand, rhs: FunctionCommand) -> Bool { return lhs.commands == rhs.commands } }