function with optionals, generics and comparable does satisfy compiler requirements - swift

Im reading up on some algorithms and im working on a binary search tree. I have made the following
class TreeNode<T: Comparable>{
var value: T
var parent: TreeNode?
var leftChild: TreeNode?
var rightChild: TreeNode?
init(value: T) {
self.value = value
}
// ... more stuff ...
Which works fine. I have search, insert and print up and running, however when im trying to implement isSame, to se if two trees are the same, the compiler wont accept any of my function declarations:
First i try:
func isSame(leftNode: TreeNode?, rightNode: TreeNode?) -> Bool {
Compiler tells me "Reference to generic type 'TreeNode' requires arguments"
and suggests adding , which i then do, but now the compiler wants me to insert a ',' after the last parameter
func isSame(leftNode: TreeNode?, rightNode: TreeNode<T: Comparable>?) -> Bool {
if I do, it suggest i add another :D
resulting in something like
func isSame(leftNode: TreeNode?, rightNode: TreeNode<T: Comparable>?,,,) -> Bool {
Compiler, I have obeyed your every command. What more do you want from me?
I can get around this by stripping the function of the generic part like this:
func isSame(leftNode: TreeNode<Int>?, rightNode: TreeNode<Int>?) -> Bool {
But im curious to what I have to do to make the function work with generic types?
TLDR: How do I make an isSame function accept these two generic arguments?
Full code:
import UIKit
class TreeNode<T: Comparable>{
var value: T
var parent: TreeNode?
var leftChild: TreeNode?
var rightChild: TreeNode?
init(value: T) {
self.value = value
}
convenience init(array: [T]){
precondition(array.count > 0) // test denne
self.init(value: array.first!)
for item in array.dropFirst(){
self.insert(item)
}
}
func insert(_ newValue: T){
if newValue < self.value {
if leftChild == nil {
leftChild = TreeNode(value: newValue)
leftChild?.parent = self
} else {
leftChild!.insert(newValue)
}
}
else {
if rightChild == nil {
rightChild = TreeNode(value: newValue)
rightChild?.parent = self
} else {
rightChild!.insert(newValue)
}
}
}
func search(_ targetValue: T) -> Bool{
if targetValue < self.value{
if let leftChild = leftChild{
return leftChild.search(targetValue)
}
}
if targetValue > self.value{
if let rightChild = rightChild{
return rightChild.search(targetValue)
}
}
if targetValue == value{
print("found \(targetValue)")
return true
}
print("did not find \(targetValue)")
return false
}
}
// MARK: - Extensions
extension TreeNode: CustomStringConvertible{
var description: String {
var s = ""
if let left = self.leftChild {
s += "(\(left.description)) <-"
}
s += " \(value) "
if let right = self.rightChild {
s += "-> (\(right.description))"
}
return s
}
}
// isSame
func isSame(leftNode: TreeNode<Int>?, rightNode: TreeNode<Int>?) -> Bool {
if ((leftNode != nil && rightNode == nil) || (rightNode == nil && leftNode != nil)){
print("xor check returned false")
return false
}
if leftNode?.value != rightNode?.value {
return false
}
if isSame(leftNode: leftNode?.leftChild, rightNode: rightNode?.leftChild){
return isSame(leftNode: leftNode?.rightChild, rightNode: rightNode?.rightChild)
} else {
return false
}
}
// MARK: - Testing
var smallTree: TreeNode<Int> = TreeNode(value: 13)
var rootNodeFromArray = TreeNode(array: [7, 2, 5, 10, 9, 1])
// isSame test
let treeA: TreeNode<Int> = TreeNode(array: [7, 2, 5, 10, 9, 1])
let treeB: TreeNode<Int> = TreeNode(array: [7, 2, 5, 10, 9, 1])

If the function is a global function, you can make it a generic function:
func isSame<T>(leftNode: TreeNode<T>?, rightNode: TreeNode<T>?) -> Bool {
This is exactly how the Equatable protocol can be implemented:
func == <T: Equatable>(lhs: TreeNode<T>, rhs: TreeNode<T>) -> Bool {
return lhs.value == rhs.value
&& lhs.leftChild == rhs.leftChild
&& lhs.rightChild == rhs.rightChild
}
Note that the Equatable protocol doesn't need optional parameters. The comparison with nil is handled automatically.
Then you can simply compare using leftNode == rightNode.

You could put the isSame function inside the class like this:
class TreeNode<T: Comparable> {
// code here
class func isSame(leftNode: TreeNode<T>?, rightNode: TreeNode<T>?) -> Bool {
// code here
return true
}
}

Related

how verify if a method was called in a concrete class at unit test in swift

I have this scenario:
class X {
init(y: ProtocolA)
func foo(){
if(y.isSomething()){
methodA()
} else {
methodB()
}
}
func methodA(){
// any
}
func methodB(){
// any
}
}
class Y : ProtocolA {
func isSomething(): Bool { return true OR false }
}
i wanna test class X,
i will mock ProtocolA to return in isSomething() method true or false in two different test to know if methodA or methodB was called.
What the best strategy to solve this?
ps: with mockito, using a Spy with verify this is very easy, but with Swift this is very painful
edit:
well, i do this:
first, the parts:
class X { init(y: Y) }
protocol Y { func isSomething() -> Bool }
now, the struct for test: mock and spy object
typealias VerifyMethodAssert = (count: Int, parameters: [Any]?, returnn: Any?)
Configurable Mock for Dependency
class YMock : Y {
init(configure: Bool)
func isSomething{ return configure }
}
Spy for concrete class
class XSpy : X {
private let y: Y
var verify: [String: VerifyMethodAssert] = [
"methodA()": (count: 0, parameters: nil, returnn: nil)
"methodB()": (count: 0, parameters: nil, returnn: nil)
]
var nothing: [String: Bool] = [
"methodA()": false
"methodB()": false
]
init(y: Y, verify: [String: VerifyMethodAssert]?, nothing: [String: Bool]?)
func methodA(){
verify["\(#function)"] = (count: verify["\(#function)"]!.count + 1, parameters: nil,
returnn: nothing["\(#function)"]! ? nil : super.methodA())
}
func methodB(doNothing: Bool = false){
verify["\(#function)"] = (count: verify["\(#function)"]!.count + 1, parameters: nil,
returnn: nothing["\(#function)"]! ? nil : super.methodB())
}
}
and test:
class XTest : QuickSpec {
override func spec(){
describe("a position view model"){
it("test 1"){
let y = Y(configure: true)
let x = XSpy(y: y)
x.foo()
expect(1).to(x.verify["methodA()"].count)
expect(0).to(x.verify["methodB()"].count)
}
it("test 2"){
let y = Y(configure: true)
let x = XSpy(y: y)
x.foo()
expect(0).to(x.verify["methodA()"].count)
expect(1).to(x.verify["methodB()"].count)
}
}
}
}
There is no out of the box way as far as I know.
One way to do it is to check a counter:
class X {
var countA: Int = 0
var countB: Int = 0
init(y: ProtocolA)
func foo(){
if(y.isSomething()){
methodA()
} else {
methodB()
}
}
func methodA(){
countA += 1
// any
}
func methodB(){
countB += 1
// any
}
}
This approach is also suggested here.
In this specific case you can subclass X and use an associated object to hold invocation counts, you can generalize this if you see yourself using it again and again:
final class TestX: X {
private struct AssociatedKeys {
static var invocations = "\(String(describing: type(of: TestX.self)))-invocations"
}
func invocations(for method: String) -> Int {
return invocations[method] ?? 0
}
private var invocations: [String: Int] {
get {
return objc_getAssociatedObject(self, &AssociatedKeys.invocations) as? [String: Int] ?? [:]
}
set {
objc_setAssociatedObject( self, &AssociatedKeys.invocations, newValue as NSDictionary, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
override func methodA(){
super.methodA()
invocations["methodA"] = (invocations["methodA"] ?? 0) + 1
}
override func methodB(){
super.methodB()
invocations["methodB"] = (invocations["methodB"] ?? 0) + 1
}
}
let x = TestX(y: Y())
x.invocations(for: "methodA") //0
x.foo()
x.invocations(for: "methodA") //1

argument type 'T.Type' does not conform to expected type 'Comparable'

I am trying to create a small class in swift but getting the following error argument type T.Type does not conform to expected type Comparable
Can someone help?
struct BST<T: Comparable> {
let root: Node<T>?
var count = 0
init<T:Comparable>(data: T) {
self.root = Node(data : T) //Error Occurs in this line
}
}//end class BST
Here is code of Node class.
class Node<T: Comparable> {
let data: T
var left: Node?
var right: Node?
init(data: T) {
self.data = data
} //end init
} //end class node
func == <T> (lhs: Node<T>, rhs: Node<T>) -> Bool {
return lhs.data == rhs.data
} //end ==
func < <T> (lhs: Node<T>, rhs: Node<T>) -> Bool {
if(rhs.data > lhs.data) {
return true
}
return false
} //end fun <
You need to pass data in the initializer not T. and also there is no need to make initialize generic.
Change your code:
struct BST<T: Comparable> {
let root: Node<T>?
var count = 0
init(data: T) {
self.root = Node(data: data)
}
}//end class BST
self.root = Node(data : T) //Error Occurs in this line
You are trying to initialize a Node with the type, instead of the value.
Try
self.root = Node(data : data)

Extending a Collection where the Element type is generic (Swift)

It's simple to extend a Collection type in swift to have a custom function for particular Element types:
struct MyStruct {
let string: String
}
extension Set where Element == MyStruct {
func getFirstWith(string: String) -> Element? {
return filter({ $0.string == string }).first
}
}
But suppose your Element type is generic?
protocol MyProtocol {}
struct MyGenericStruct<T: MyProtocol> {
let string: String
}
// error on next line:
// error: expected '>' to complete generic argument list
// extension Set where Element == MyGenericStruct<T: MyProtocol> {
// ^
extension Set where Element == MyGenericStruct<T: MyProtocol> {
func getFirstWith(string: String) -> Element? {
return filter({ $0.string == string }).first
}
}
// error on next line:
// error: use of undeclared type 'T'
// extension Set where Element == MyGenericStruct<T> {
// ^
extension Set where Element == MyGenericStruct<T> {
func getFirstWith(string: String) -> Element? {
return filter({ $0.string == string }).first
}
}
It's unclear to me how to declare that my element is a generic.
Details
Swift 3.1, xCode 8.3.3
Solution
import Foundation
struct MyStruct:Hashable {
let string: String
static func == (lhs: MyStruct, rhs: MyStruct) -> Bool {
return lhs.string == rhs.string
}
var hashValue: Int {
return string.hash
}
}
extension Set where Element == MyStruct {
func getFirstWith(string: String) -> Element? {
return filter({ $0.string == string }).first
}
}
var set = Set<MyStruct>()
set.insert(MyStruct(string: "123"))
set.insert(MyStruct(string: "231"))
print(String(describing:set.getFirstWith(string: "123")))
print(String(describing:set.getFirstWith(string: "231")))
///////////////////////////////////
protocol MyProtocol {}
struct MyType1: MyProtocol {}
struct MyType2: MyProtocol {}
struct MyGenericStruct<T: MyProtocol>: Hashable {
let string: String
static func == (lhs: MyGenericStruct, rhs: MyGenericStruct) -> Bool {
return lhs.string == rhs.string
}
var hashValue: Int {
return string.hash
}
}
extension Set where Element == AnyHashable {
func getFirstWith(string: String) -> Element? {
return filter{ element -> Bool in
if let _element = element as? MyGenericStruct<MyType1> {
if _element.string == string {
return true
}
}
if let _element = element as? MyGenericStruct<MyType2> {
if _element.string == string {
return true
}
}
return false
}.first
}
}
var set2 = Set<AnyHashable>()
set2.insert(MyGenericStruct<MyType1>(string: "abc"))
set2.insert(MyGenericStruct<MyType2>(string: "cba"))
print(String(describing: set2.getFirstWith(string: "abc")))
print(String(describing:set2.getFirstWith(string: "cba")))
Result
Answering my own question here on request.
I was unable to figure out how to make this an extension on Set.
Instead, we wrote a little utility function. Not as clear as a extension, but gets the work done. It looks like this:
func getFirst<T: MyProtocol>(fromSet set: Set<MyGenericStruct<T>>, whereStringIs string: String) -> MyGenericStruct<T>? {
return set.first(where: { $0.string == string })
}
As others have noted, MyGenericStruct needs to be Hashable.
If I do understand the purpose, you probably need to have more implementation in your protocol and structure.
First, element's protocol has to be hashable and equitable.
protocol MyProtocol: Hashable, Equatable {
var string: String { get }
}
Therefore, MyGenericStruct will look like the following.
struct MyGenericStruct: MyProtocol {
let string: String
var hashValue: Int {
get {
return string.hashValue
}
}
static func ==(lhs: MyGenericStruct, rhs: MyGenericStruct) -> Bool {
return lhs.hashValue == rhs.hashValue
}
}
Then, declare extension with constraints specified by a where clause for MyProtocol
extension Set where Element: MyProtocol {
func getFirstWith(string: String) -> Element? {
return filter({$0.string == string}).first
}
}
Finally, let's do a test and see its result.
// Example
let set: Set = [
MyGenericStruct(string: "Watermelon"),
MyGenericStruct(string: "Orange"),
MyGenericStruct(string: "Banana")
]
let output = set.getFirstWith(string: "Orange")
print(output)
In my playground with Xcode 8, I can get Optional(MyGenericStruct(string: "Orange")) in log.
[UPDATED1] To make an Extension on Set<MyGenericStruct> only:
extension Set where Element == MyGenericStruct {
func getFirstWith(string: String) -> Element? {
return filter({$0.string == string}).first
}
}
[UPDATED2] In case to keep MyGenericStruct<T: MyProtocol> declaration as stated is necessary, another approach to implement Set extension:
protocol MyProtocol {
}
struct BaseStruct1: MyProtocol {
}
struct BaseStruct2: MyProtocol {
}
protocol ContainStringProtocol: Hashable {
var string: String { get }
}
struct MyGenericStruct<T: MyProtocol>: ContainStringProtocol {
var string: String
var hashValue: Int {
get {
return string.hashValue
}
}
init(string: String) {
self.string = string
}
static func ==(lhs: MyGenericStruct, rhs: MyGenericStruct) -> Bool {
return lhs.hashValue == rhs.hashValue
}
}
extension Set where Element: ContainStringProtocol {
func getFirstWith(string: String) -> Element? {
return filter({$0.string == string}).first
}
}
// Example
let set1: Set = [
MyGenericStruct<BaseStruct1>(string: "Watermelon"),
MyGenericStruct<BaseStruct1>(string: "Orange"),
MyGenericStruct<BaseStruct1>(string: "Banana")
]
let output1 = set1.getFirstWith(string: "Orange")
print(output1!)
let set2: Set = [
MyGenericStruct<BaseStruct2>(string: "Watermelon"),
MyGenericStruct<BaseStruct2>(string: "Orange"),
MyGenericStruct<BaseStruct2>(string: "Banana")
]
let output2 = set2.getFirstWith(string: "Orange")
print(output2!)

Swift Generic issue

I am following this Generic tutorial from Apple https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Generics.html.
But in the end of tutorial. I got some problem with this:
var myStack = Stack<String>()
myStack.push("a")
myStack.push("b")
myStack.push("c")
var arrayOfStrings = ["a", "b", "c"]
if allItemsMatch(myStack, arrayOfStrings) {
print("All items match.")
} else {
print("Not all items match.")
}
at the line if allItemsMatch(myStack, arrayOfStrings), it says:
Cannot invoke 'allItemsMatch' with an argument list of type
'(Stack< String>, [String])'
Here is my code:
import UIKit
struct Stack<Element> {
var items = [Element]()
mutating func push(item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
}
extension Stack {
var topItem: Element? {
return items.isEmpty ? nil : items[items.count - 1]
}
mutating func append(item: Element) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> Element {
return items[i]
}
}
func findIndex<T: Equatable>(array: [T], _ valueToFind: T) -> Int? {
for (index, value) in array.enumerate() {
if value == valueToFind {
return index
}
}
return nil
}
let doubleIndex = findIndex([3.14159, 0.1, 0.25], 9.3)
let stringIndex = findIndex(["Mike", "Malcolm", "Andrea"], "Andrea")
protocol Container {
associatedtype ItemType
mutating func append(item: ItemType)
var count: Int { get }
subscript(i: Int) -> ItemType { get }
}
extension Array: Container {}
func allItemsMatch< C1: Container, C2: Container where C1.ItemType == C2.ItemType, C1.ItemType: Equatable> (someContainer: C1, _ anotherContainer: C2) -> Bool {
if someContainer.count != anotherContainer.count {
return false
}
for i in 0..<someContainer.count {
if someContainer[i] != anotherContainer[i] {
return false
}
}
return true
}
var myStack = Stack<String>()
myStack.push("a")
myStack.push("b")
myStack.push("c")
var arrayOfStrings = ["a", "b", "c"]
if allItemsMatch(myStack, arrayOfStrings) {
print("All items match.")
} else {
print("Not all items match.")
}
Am I missing somewhere?
You never explicitly conform your Stack<Element> struct to your Container protocol. Therefore Swift's strict type safety will prevent you from passing it into a parameter that expects something that conforms to the Container protocol (even if it implicitly conforms).
You can explicitly conform your Stack to Container via an extension. For example:
extension Stack:Container {}

Why doesn't this generic set implementation for Swift work?

I'm trying to implement a simple mutable set as a way to learn Swift, but the code below gives me the following compiler error for the add and remove methods:
Could not find an overload for 'subscript' that accepts the supplied arguments
What am I doing wrong?
class SwiftSet<T: Hashable> {
let _underlyingSet: Dictionary<T, Bool>
init() {
_underlyingSet = Dictionary<T, Bool>()
}
subscript(k: T) -> Bool {
if _underlyingSet[k] {
return true
}
else {
return false
}
}
func contains(k: T) -> Bool {
return self[k]
}
func add(k: T) {
_underlyingSet[k] = true
}
func remove(k: T) {
_underlyingSet[k] = nil
}
func allObjects() -> T[] {
return Array(_underlyingSet.keys)
}
}
Because you're trying to modify an immutable constant defined with let _underlyingSet in your add() and remove() methods.
If you want to modify a variable after initialization you should change it to var _underlyingSet, i.e:
class SwiftSet<T: Hashable> {
var _underlyingSet: Dictionary<T, Bool>
init() {
_underlyingSet = Dictionary<T, Bool>()
}
subscript(k: T) -> Bool {
if _underlyingSet[k] {
return true
}
else {
return false
}
}
func contains(k: T) -> Bool {
return self[k]
}
func add(k: T) {
_underlyingSet[k] = true
}
func remove(k: T) {
_underlyingSet[k] = nil
}
func allObjects() -> T[] {
return Array(_underlyingSet.keys)
}
}
You've declared _underlyingSet as a constant, so it doesn't have a defined setter for its subscript. Change its declaration to:
var _underlyingSet: Dictionary<T, Bool>