kazuochi
kazuochi

Reputation: 230

Extend swift array that hold specific element type

I've been trying to extend a swift array that hold specific type.

protocol Node {
  var nodeId: Int { get }
  var parentId: Int? { get }
  var children: [Node]  { get set }
  var level: Int { get set }
}

extension Array where Element : Node {
/**
unflatten an array of Nodes.
*/
func unflattenNodes()-> [Node] {

    func unflatten(inout parent: Node?)-> [Node] {

        var topNodes = [Node]()
        let children = self.filter{ (child: Node) in return child.parentId == parent?.nodeId ?? 0 }

        if !children.isEmpty {

            if var parent = parent {
                for var child in children {
                    child.level = parent.level + 1
                }
                parent.children = children
            }
            else {
                topNodes = children
            }

            for child in children {
                var optChild = Optional(child)
                unflatten(&optChild)
            }
        }
        return topNodes;
    }

      var optChild: Node? = nil
      return unflatten(&optChild)
 }
}

This code above won't be compiled because 'Node' is not subtype of 'Element', even though I'm extending Array of element "Node". How can I archive what I'm trying to do here in swift? I'm trying to add an instance method to [Node] to unflatten self.

Upvotes: 0

Views: 633

Answers (3)

kazuochi
kazuochi

Reputation: 230

Updating extension Array where Element : Node to extension CollectionType where Generator.Element == Node resolved the error.

Upvotes: 1

JeremyP
JeremyP

Reputation: 86651

Right, I've plugged the code into Playground and I found three issues. The first is the one mentioned by Kametrixom which is that you need to use Element as the type everywhere in unflattenNodes. When you have fixed that and got rid of all the parent: in the calls to unflatten, you'll be left with one error

parent.children = children
error: cannot assign a value of type '[Element]' to a value of type '[Node]'
                parent.children = children
                                  ^

This is caused by the fact that the children property in the protocol is defined as [Node] and Swift can't match it to an array of Element

So you need to change the protocol

protocol Node {
    var nodeId: Int { get }
    var parentId: Int? { get }
    var children: [Self]  { get set }
    //            ^^^^^^ Here
    var level: Int { get set }
}

The children property is no longer an array of Node but an array of whatever type is conforming to the protocol, in your case, Element

Upvotes: 1

Kametrixom
Kametrixom

Reputation: 14973

The problem is that the protocol Node doesn't conform to itself: Node is not of type Node (as contradicting as it sounds), because a protocol isn't a concrete type, it's just a requirement for the conforming type.

That said, you need to replace every instance of Node in your code with Element, then it should work (can't test it right now). This is because again, you're actually not handling some value of type Node, but rather a value of a type that conforms to Node (Element in your case)

Also you made a few other mistakes in your code, I'll leave that to someone else to correct as I'm out of time.

Upvotes: 1

Related Questions