I have created a class that adopt Hashable protocol.
So I created some instances of this class with different properties and added them to the Set.
Then I change a property of an object.
After this change the Set sometimes fail .contains (and also .remove).
In the debugger inspector I see that the object has the same memory address of the element inside the Set. So why fail at random?
Note that I can always found the index of the element inside the set.
I tested with playground (on xcode10) several times and on every execution the results change.
class Test: Hashable {
// MARK: Equatable protocol
static func == (lhs: Test, rhs: Test) -> Bool {
return lhs === rhs || lhs.hashValue == rhs.hashValue
}
var s: String
func hash(into hasher: inout Hasher) {
hasher.combine(s.hashValue)
}
init(s: String) {
self.s = s
}
}
func test(s: Set<Test>, u: Test) -> Bool {
if s.contains(u) {
print("OK")
return true
} else {
print("FAIL") // SOMETIMES FAIL
if !s.contains(u) {
if let _ = s.firstIndex(where: { $0 == u }) {
print("- OK index") // ALWAYS OK
return true
} else {
print("- FAIL index") // NEVER FAIL
return false
}
} else {
return true
}
}
}
var s: Set<Test> = []
let u1 = Test(s: "a")
s.insert(u1)
let u2 = Test(s: "b")
s.insert(u2)
test(s: s, u: u2)
u2.s = "c"
test(s: s, u: u2)
u2.s = "d"
test(s: s, u: u2)
u2.s = "b"
test(s: s, u: u2)
From the docs on NSSet:
If mutable objects are stored in a set, either the hash method of the objects shouldn’t depend on the internal state of the mutable objects or the mutable objects shouldn’t be modified while they’re in the set.
I think that exactly covers this case. True, it's about Cocoa NSSet, but I would expect Swift Set to correspond to NSSet in this regard.
Just for the record, I was able to reproduce the behavior you describe, eliminating some of the skankier or more questionable code - not in a playground, with a legal implementation of == and using hashValue, and without the unnecessary call to a test function:
class Test: Equatable, Hashable, CustomStringConvertible {
var s: String
static func == (lhs: Test, rhs: Test) -> Bool {
return lhs.s == rhs.s
}
var hashValue: Int {
return s.hashValue
}
init(s: String) {
self.s = s
}
var description: String {
return "Test(\(s))"
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
var s: Set<Test> = []
let u1 = Test(s: "a")
s.insert(u1)
let u2 = Test(s: "b")
s.insert(u2)
print(s.contains(u2))
u2.s = "c"
print(s.contains(u2))
}
}
To test it, run the project over and over. Sometimes you'll get true true and sometimes you'll get true false. The inconsistency is the indication that you shouldn't be mutating an object in a set.
Things in a set should be immutable.
You should never have put Test objects into a set because Test is completely mutable. This is exactly why you get these "strange and random" behaviour.
When you call contains, the set (or rather, the underlying hash table) evaluates the hash code of the parameter and see if the hash code matches any of the hash codes in the set. (Note that this is an oversimplification and it makes it sounds like this is a O(n) operation. It's not.)
Before you change u2, it has a hash code of x. The set remembers that u2 has a hash code of x. Now you change u2. It now has a different hash code y. The set thus can't find an element in it that has a hash code of y.
So basically, you should make sure that everything you put into a set has a constant hash code.
You can make Test immutable by doing:
let s: String
If you want to learn more you can look up how the set data structure is implemented in Swift. I found this post which might help as well.
Since you are using the s property of Test class to create the hash values, try comparing s values instead of comparing the objects, i.e.
static func == (lhs: Test, rhs: Test) -> Bool
{
return lhs.s == rhs.s
}
This will resolve your issue. Also, as I mentioned in the comment, there is no need to use an extra if-else in the failure case. You can simply use the below code:
func test(s: Set<Test>, u: Test) -> Bool
{
if s.contains(u)
{
print("OK")
return true
}
else
{
print("FAIL: \(u.s)") // SOMETIMES FAIL
return false
}
}
Related
I have an array of functions like
let array = [(Int) -> T?, (Int) -> T?, (Int) -> T?,...]
I need to get first non nil T value from array and I want 1 iteration for this task (O(n) will be the worst complexity). Anybody has neat ideas without for loops?
As I mentioned in my comment, there's no ready-made way to do this in Swift, so you have to at least implement something that uses a for loop.
If you want appearances at the call-site to look functional and not use a for loop, you can make the function extend Array like so:
extension Array {
func firstNonNilResult<V, T>(value: V) -> T? where Element == (V) -> T? {
for element in self {
if let t = element(value) {
return t
}
}
return nil
}
}
var array = [(Int) -> String?]()
func f(_ i: Int) -> String? {
print("called f() with \(i)")
return nil
}
func g(_ i: Int) -> String? {
print("called g() with \(i)")
return i == 5 ? "found it" : nil
}
array.append(f)
array.append(g)
if let t = array.firstNonNilResult(value: 5) {
print(t)
}
which prints:
called f() with 5
called g() with 5
found it
Whether or not this has any real-world utility I can't say. I think it's specialized enough that an Array extension seems like overkill, but your question is interesting so this is at least a potential solution.
Suppose you have two closures of type (Int)->() in Swift 3 and test to see if they are the same as each other:
typealias Baz = (Int)->()
let closure1:Baz = { print("foo \($0)") }
let closure2:Baz = { print("bar \($0)") }
if(closure1 == closure2) {
print("equal")
}
This fails to compile, giving the message:
Binary operator '==' cannot be applied to two '(Int)->()' operands
OK, well, how then can we compare two closures of the same type, to see if they are the same?
I'm pretty sure there is no way to determine if two closures are equal.
Obviously, a logical equality check is out of the question. That would be equivalent to finding an answer to the halting problem. (Just test to see if your code is equivalent to a piece of code that loops forever. If it is, it doesn't halt. If it isn't, it does halt.)
In theory you might expect the === operator to test if two closures are the exact same piece of code, but that gives an error when I try it in Playground.
Playground execution failed: error: MyPlayground.playground:1:20: error: cannot check reference equality of functions; operands here have types '(Int) -> ()' and '(Int) -> ()'
let bar = closure1 === closure2
~~~~~~~~ ^ ~~~~~~~~
Having thought about it, I'm sure the reason why that doesn't work is because you can't be sure that the closures really are equal. A closure is not just the code, but also the context in which it was created including any captures. The reason you can't check for equality is that there is no meaningful way in which two closures are equal.
To understand why thew captures are important, look at the following code.
func giveMeClosure(aString: String) -> () -> String
{
return { "returning " + aString }
}
let closure1 = giveMeClosure(aString: "foo")
let closure2 = giveMeClosure(aString: "bar")
Are closure1 and closure2 equal? They both use the same block of code
print(closure1()) // prints "returning foo"
print(closure2()) // prints "returning bar"
So they are not equal. You could argue that you can check the code is the same and the captures are the same, but what about
func giveMeACount(aString: String) -> () -> Int
{
return { aString.characters.count }
}
let closure3 = giveMeACount(aString: "foo")
let closure4 = giveMeACount(aString: "bar")
print(closure3()) // prints 3
print(closure4()) // prints 3
Apparently these closures are equal. It's not possible to implement any reasonable definition of equality that will work in every case, so Apple has instead not even tried. This is safer than providing an incomplete implementation that is wrong in some cases.
In the case where you want to track your own closures, uses them as Dictionary keys, etc., you can use something like this:
struct TaggedClosure<P, R>: Equatable, Hashable {
let id: Int
let closure: (P) -> R
static func == (lhs: TaggedClosure, rhs: TaggedClosure) -> Bool {
return lhs.id == rhs.id
}
var hashValue: Int { return id }
}
let a = TaggedClosure(id: 1) { print("foo") }
let b = TaggedClosure(id: 1) { print("foo") }
let c = TaggedClosure(id: 2) { print("bar") }
print("a == b:", a == b) // => true
print("a == c:", a == c) // => false
print("b == c:", b == c) // => false
I want to make RxSwift and Realm work together, and I tried to build functions to help me.
For example, instead of using the function sorted on Results objects (which give you sorted Results), I want to build a function that do so directly on Observable>.
Thanks to the ObservableType protocol, I managed to do it on non-generic object, but can't find a way to do it on a generic way
Here is my actual code, which works only on specific Object :
public extension ObservableType where E == Results<MyRealmObject> {
public func sorted(key: String, ascending: Bool = true) -> Observable<Results<MyRealmObject>>
{
return self.map { $0.sorted(key, ascending: ascending) }
}
}
If I changed MyRealmObject by T, the compilers tell me that T is undeclared.
I've tried many syntaxes but none are working, and I don't know if it's possible.
I don't have these frameworks, but I'm guessing the types are analogous to the following:
protocol ObservableType {
associatedtype E
}
class Observable<T> : ObservableType {
typealias E = T
init() {}
}
enum Results<T> {
case None
case Some(T)
}
... in which case you could try:
extension ObservableType {
func sorted <T where Self.E == Results<T>> (/* ... */) -> Observable<Results<T>> {
return /* sorted */ Observable()
}
}
... which works:
let o = Observable<Results<Int>>()
o.sorted() // Observable<Results<Int>>
... but is not optimal because:
let x = Observable<Int>()
x.sorted() // compile-time error: Generic parameter `T` could not be infered
... which you'd prefer to say Value of type 'Observable<Int>' has no member 'sorted'. And though the error is at least thrown at compile time, I think your own approach is still preferable.
Just an afterthought based on #Denis Laboureyras' comments
Whilst trying out my solution, Denis could not access the value of type E as Results<T> without casting because the extension does not constrain the type of self but only the parameters of the method. All these issues go away in case of a free function (though I appreciate this is not ideal either):
protocol ObservableType {
associatedtype E
func map <X> (_: E -> X) -> Observable<X>
}
class Observable<T> : ObservableType {
typealias E = T
init() {}
func map <X> (f: E -> X) -> Observable<X> {
return Observable<X>(/* with f(e) */)
}
}
class Results<T> {
func sort(/* ... */) -> Results<T> {
return /* sorted */ self
}
}
func sort <O: ObservableType, T where O.E == Results<T>> (o: O/* ... */) -> Observable<Results<T>> {
return o.map{ $0.sort() }
}
let o = Observable<Results<Int>>()
sort(o) // Observable<Results<Int>>
I created a class which is meant to be used as an "abstract class" (only to be subclassed, not instantiated directly). Since Swift doesn't support this, is has to be emulated using e.g. fatalError in body of abstract method.
My abstract class has to be equatable. So I thought, I use fatalError in equals method:
class MySuperClass:Equatable {
}
func ==(lhs: MySuperClass, rhs: MySuperClass) -> Bool {
fatalError("Must override")
}
class MySubClass:MySuperClass {
let id:Int
init(_ id:Int) {
self.id = id
}
}
func ==(lhs: MySubClass, rhs: MySubClass) -> Bool {
return lhs.id == rhs.id
}
let a = MySubClass(1)
let b = MySubClass(2)
let c = MySubClass(2)
a == b
b == c
And this works. I have the little problem though that my subclass has a type parameter. Now the example looks like this:
class MySuperClass:Equatable {
}
func ==(lhs: MySuperClass, rhs: MySuperClass) -> Bool {
fatalError("Must override")
}
class MySubClass<T>:MySuperClass {
let id:Int
init(_ id:Int) {
self.id = id
}
}
func ==<T>(lhs: MySubClass<T>, rhs: MySubClass<T>) -> Bool {
return lhs.id == rhs.id
}
let a = MySubClass<Any>(1)
let b = MySubClass<Any>(2)
let c = MySubClass<Any>(2)
a == b
b == c
And now it crashes, because it doesn't "see" the overriding equals, and it executes only equals in the superclass.
I know Swift has some issues concerning overrides using generic types. I thought though that this was limited to interaction with obj-c. This looks at least like a language deficiency, or bug, why would equals of generic class B not override equals of class A, if B is a subclass of A?
As Airspeed suggests the problem is that operator's implementation is not a part of class/struct implementation => hence, inheritance does not work there.
What you can do is to keep the logic inside of the class implementation and make operators use it. E.g. the following will do what you need:
class MySuperClass: Equatable {
func isEqualTo(anotherSuperClass: MySuperClass) -> Bool {
fatalError("Must override")
}
}
func == (lhs: MySuperClass, rhs: MySuperClass) -> Bool {
return lhs.isEqualTo(rhs)
}
class MySubClass<T>:MySuperClass {
let id: Int
init(_ id: Int) {
self.id = id
}
override func isEqualTo(anotherSuperClass: MySuperClass) -> Bool {
if let anotherSubClass = anotherSuperClass as? MySubClass<T> {
return self.id == anotherSubClass.id
}
return super.isEqualTo(anotherSuperClass) // Updated after AirSpeed remark
}
}
let a = MySubClass<Any>(1)
let b = MySubClass<Any>(2)
let c = MySubClass<Any>(2)
a == b
b == c
... as you can see == operator is defined only once and it uses MySuperClass's method to figure out whether its two arguments are equal. And after that .isEqualTo() handles the rest, including the use of inheritance mechanism on MySubClass level.
UPD
The benefit of above approach is that the following will still work:
let a2: MySuperClass = a
let b2: MySuperClass = b
let c2: MySuperClass = c
a2 == b2
b2 == c2
... i.e. regardless of the variable type at compile-time the behaviour will be determined by the actual instance type.
In overloading resolution, non-generic functions always have priority over generic ones, so the lesser rule that functions taking subclasses precede ones taking superclasses isn't taken into account.
A possible solution is to make the superclass == generic too. That way the rules for choosing between two generic functions kick in, and in this case the more specific one is the one taking specific classes parameterized by T:
func ==<T: MySuperClass>(lhs: T, rhs: T) -> Bool {
// bear in mind, this is a question of compile-time overloading,
// rather than overriding
fatalError("Must override")
}
func ==<T>(lhs: MySubClass<T>, rhs: MySubClass<T>) -> Bool {
return lhs.id == rhs.id
}
let a = MySubClass<Any>(1)
let b = MySubClass<Any>(2)
let c = MySubClass<Any>(2)
// no longer asserts
a == b
b == c
I implemented a helper to have an array of unowned references:
class Unowned<T: AnyObject>
{
unowned var value : T
init (value: T) { self.value = value }
func get() -> T { return self.value }
}
Now, it is possible to do [ Unowned<Foo> ]. However, I'm not satisfied with having the additional get() method to retrieve the underlying object. So, I wanted to write a custom binary operator, e.g. --> for being able to do
for unownedFoo in ArrayOfUnownedFoos
{
var bar : Int = unownedFoo-->method()
}
My current approach is to define
infix operator --> { }
func --><T> (inout lhs: Unowned<T>, inout rhs: () -> Int) -> Int
{
}
The idea I had behind this is:
lhs is obvisouly the object I get out of the array, on which I want to perform the call on
rhs is the method I desire to call. In this case method() would not take no parameters and return an Int, and therefore
The return value is int.
However, the following problems / uncertainties arise:
Is this the correct approach?
Are my assumptions above correct?
How can I call the provided closure rhs on the instance of the extracted Unowned<T>, e.g. (pseudocode) lhs.value.rhs(). If method() was static, I could do T.method(lhs.value), but then I would have to extract the name of the method somehow to make it more generic.
Maybe, a postfix operator is rather simple.
postfix operator * {}
postfix func *<T>(v:Unowned<T>) -> T {
return v.value
}
// Usage:
for unownedFoo in ArrayOfUnownedFoos {
var bar : Int = unownedFoo*.method()
}
Use something like:
func --> <T:AnyObject, V> (lhs: Unowned<T>, rhs: (T) -> V) -> V
{
return rhs (lhs.get())
}
and then use it as:
for unownedFoo in ArrayOfUnownedFoos
{
var bar : Int = unownedFoo-->{ (val:Int) in return 2*val }
}
Specifically, you don't want to use method() as that itself is a function call - which you probably don't want unless method() is actually returning a closure.