realm-swift icon indicating copy to clipboard operation
realm-swift copied to clipboard

Comparing a `Map<String, DynamicObject?>` to itself is not commutative. (i.e., sometimes returns the wrong result)

Open lukaskollmer opened this issue 1 year ago • 0 comments

How frequently does the bug occur?

Always

Description

Consider the following program:

class Foo: Object {
    @Persisted var map: Map<String, Bar?>
}

class Bar: Object {
    @Persisted var title: String
}

let realm = try Realm(configuration: .init(inMemoryIdentifier: UUID().uuidString))

try realm.write {
    realm.add(Foo(value: [
        "map": [
            "abc": Bar(value: ["title": "text"])
        ]
    ]))
}


let dynFoo = realm.dynamicObjects("Foo").first!

let dynMap1 = dynFoo.dynamicMap("map") as Map<String, DynamicObject?>
let dynMap2 = dynFoo["map"] as! Map<String, DynamicObject?>

print(dynMap1 == dynMap2, dynMap2 == dynMap1)
// expected: true, true
// actual: true, false

This program defines a simple data model consisting of two classes, one of which contains a Map, with the other class as the value. When we then to access the Map property via a DynamicObject (once via a subscript, and once via the dynamicMap(_:) function), the two returned objects — despite pointing to the same property — only compare as equal if the one returned from dynamicMap(_:) is on the left-hand side of the == operator. However, if the order is reversed, the comparison evaluates to false.

Note: I did some additional testing here, and it seems that this only happens when acceessing the Map property through a DynamicObject. For example, trying to run the same comparison on a non-dynamic Foo object works fine (i'm adding the RLMSwiftCollectionBase cast here to give the objects the same static type, since it'd be Map<String, Foo?> and Map<String, DynamicObject?> otherwise):

let foo = realm.objects(Foo.self).first!
let map1 = foo["map"] as! RLMSwiftCollectionBase
let map2 = foo.dynamicMap("map") as Map<String, DynamicObject?> as! RLMSwiftCollectionBase
print(map1 == map2, map2 == map1)
// output: true, true

It also does not seem to be related to the Map type, since changing the static type of the dynMap{1,2} variables to RLMSwiftCollectionBase does not fix the issue.

Stacktrace & log output

n/a

Can you reproduce the bug?

-- select --

Reproduction Steps

Run the program above.

Version

RealmSwift 10.44.0

What Atlas Services are you using?

Local Database only

Are you using encryption?

No

Platform OS and version(s)

macOS 14.1

Build environment

Xcode version: Xcode 15.0.1 Dependency manager and version: SPM

lukaskollmer avatar Nov 09 '23 11:11 lukaskollmer