Ankur Arya
Ankur Arya

Reputation: 4723

Instance member as default parameter

I am trying to use a property root as default parameter in add function as below and it is giving me an error:

Cannot use instance member 'root' as a default parameter .

However, when I am using root in a nested function search it is working fine.

class Trie {
   var root = TrieNode()

   func add(value: String, node: TrieNode? = root) { // error
      var myNode = node
      if myNode == nil {
        myNode = root
      }
      if value.count == 0 {
        node?.setEnd()
        return
      } else if myNode!.keys[String(value.first!)] == nil {
        myNode!.keys[String(value.first!)] = TrieNode()
        return add(value: String(value.dropFirst()), node: myNode!.keys[String(value.first!)])
    } else {
        return add(value: String(value.dropFirst()), node: myNode!.keys[String(value.first!)])
    }
   }


  func allWords() -> [String] {
    var words = [String]()
    func search(node: TrieNode = root, string: String) { // Here it is working fine.
        if node.keys.count != 0 {
            for key in node.keys.keys {
                search(node: node.keys[key]!, string: string+key)
            }
            if node.isEnd {
                words.append(string)
            }
        } else {
            if string.count > 0  {
                words.append(string)
            }
        }
    }

    search(node: self.root, string: "")
    return words
}
}

Can someone tell me why I am not able to use a property as the default parameter?

Upvotes: 5

Views: 4482

Answers (2)

Paulw11
Paulw11

Reputation: 114975

Other answers have explained why you can't do it.

I suggest that the simplest way to achieve what you want is via the nil coalescing operator

func add(value: String, node: TrieNode? = nil) { // error
  var myNode = node ?? root

  guard let key = value.first, keyStr = String(key) else {
      myNode.setEnd()
      return
  }

  let updateNode = myNode.keys[keyStr, default: TrieNode()]
  return add(value: String(value.dropFirst(), node: updateNode)
 }

Upvotes: 4

Asperi
Asperi

Reputation: 258117

The reason is in different context visibility, the arguments context of interface function is external in relation to class declaration, so members are not visible, but nested function is declared inside class context, as other function body, so members are visible.

So the solution might be static, as already proposed, but it might have drawbacks (eg. for reference default members), so I recommend to use it only for constants.

The other possible solutions is below

func add(value: String, node: TrieNode?) { // no error
    func _add(value: String, node: TrieNode? = root) { // in-context
        var myNode = node
        if myNode == nil {
            myNode = root
        }
        if value.count == 0 {
            node?.setEnd()
            return
        } else if myNode!.keys[String(value.first!)] == nil {
            myNode!.keys[String(value.first!)] = TrieNode()
            return add(value: String(value.dropFirst()), node: myNode!.keys[String(value.first!)])
        } else {
            return add(value: String(value.dropFirst()), node: myNode!.keys[String(value.first!)])
        }
    }
    _add(value: value, node: node)
}

Upvotes: 6

Related Questions