Pointers, WeakRefs, and Introspection

I want to have a dictionary of weakRef’s. They need to be weakref’s because I don’t want it to be in the dictionary if all other references to it are gone. But I also need to be able when passed an object, to tell if it is in the dictionary.

How would I implement this?

  1. I need to know how to add the weak ref’s to the dictionary
  2. I need to know how to check if the object is in the dictionary

I’m thinking I might be making this more complicated in my head than it needs to be, but I want to make sure I do it right.

What kind of object are you creating WeakRefs of? And why do you need to check if it’s in the Dictionary?

I ask because you can’t do what you want to do with a WeakRef as a Dictionary key. When you create a WeakRef, it’s its own object, even if the WeakRef points to the same object as another WeakRef. But there may be another way to achieve your ultimate goal, if only I knew what that was. :slight_smile:

I’m creating a class called DatabaseCoordinator. It provides a seemless way to communicate between Xojo Objects and Database records.

For example:
Dim dc as new DatabaseCoordinator(db) //DB being a database you pass to set it up
Dim c as new Contact
dc.CoordinateClass© //Using introspection this will create or update a table on the database called Contacts
//^It will also ensure the table has the proper columns of the proper datatypes.

//Here’s where things get tricky
Dim nc as new Contact
nc.name = Joe
dc.save(nc) //This will know to create Joe as a new record on the contacts table
nc.name = Joseph
dc.save(nc) //This will know to update the record

In order for me to know whether to create/update a record I need to be able to associate the Xojo objects with what their table/index in the database is. In order to do this I want to create a Dictionary, but I want the dictionary to have weakreferences so that the class doesn’t run into memory issues.

You will have to loop over entries in dictionary and get each weakref and compare values.

Store this information in the object itself. Don’t try to keep it in an unrelated dictionary, collection, or array.

I agree, once the dc creates the record, it could store it’s uid into the nc itself.

The problem with this is there is no-where on the object itself to store it. This point of this is so you can add any object to the database without modify your classes.

It will allow any class to work simply by:
dc.CoordinateClass(c)
dc.Save(c)

Which would defeat the point of using the dictionary. Dictionaries give fast hashed lookups. But I think I just need to reverse my process. Instead of having the WeakRef’s being the Key’s, I can have them be the values…

If you could get the memory location of the instance that might work (I don’t know, can the memory manager move those around?). I thought there was a way to get this address but I think that’s only for MemoryBlocks. Maybe a simple plugin can do it?

You can’t from Xojo code.

Yeah, what Christian proposed would make performance worse than a simple array.

I’ve done this a few times. I suggest writing a WeakKeyDictionary class. It won’t (and shouldn’t) inherit from Dictionary, but it can have almost the same interface. Performance would be slower than a Dictionary, but possibly still O(1) on average, depending on how WeakRef is implemented.

Send me an e-mail and I’ll send you such a class.

Honestly doing it dynamically at run time is masochistic in Xojo.

Grab BKeeney’s Active record - grab their new tool that will generate the code for you from the database definition & it will actually help you find & avoid errors, you get all the benefits of things being strongly typed it autocompletes etc etc etc.

And enjoy the fact that the compiler can HELP you - which if you do it all with dictionaries & variants you get nothing out of.

[quote=16528:@Norman Palardy]Honestly doing it dynamically at run time is masochistic in Xojo.

Grab BKeeney’s Active record - grab their new tool that will generate the code for you from the database definition & it will actually help you find & avoid errors, you get all the benefits of things being strongly typed it autocompletes etc etc etc.

And enjoy the fact that the compiler can HELP you - which if you do it all with dictionaries & variants you get nothing out of.[/quote]

I’m familiar with Active Record, and I’m strictly trying to avoid it. My class allows you to build whatever classes you want and they will automatically save and work with the database. You get autocomplete and it is strongly typed, but you get the benefit of building your classes first instead of your database. The only place I was thinking of using a dictionary would be blackboxed from the user anyways.

[quote=16515:@Charles Yeomans]I’ve done this a few times. I suggest writing a WeakKeyDictionary class. It won’t (and shouldn’t) inherit from Dictionary, but it can have almost the same interface. Performance would be slower than a Dictionary, but possibly still O(1) on average, depending on how WeakRef is implemented.

Send me an e-mail and I’ll send you such a class.[/quote]
Brock.n@bngteam.com

I’m a “design and create the database first so you get it all properly normalized” person hence why I’d do it from the DB design and get classes that work with that design rather than try & design the right set of classes and then make the DB fit that.

And from an indexing, optimizing standpoint I will still being doing that from the start, but you do it once from the start and then never have to worry about it again. You can just change your classes and everything will work.

I’d love to believe you design the DB once & never touch it again but my years of software development says that aint so :stuck_out_tongue:
They evolve just like any other part of your software as you need to support new requirements.

My apologies for digging up an old thread, but I was curious to see if I could implement this.
To implement goal 1 from the OP, I decided to use the hash function of the variant, as keys in a dictionary. Storing a weakref as the values for those keys.
For goal 2: You use the same hash function as before and check if there is a matching hash in the dictionary. You then need to see if the weakref is still valid, if not its a hash re-use.

Ive included a verbose skeleton class that allows you to add objects as weak references, and check if an object is in the dictionary. As well as a small usage example.

I based my class off the following points from the docs:

  • Variant.Hash: For objects, it is guaranteed to be unique among all objects currently in existence (though once an object dies, a future object may use the same hash value).
  • If you compare objects, = compares their references, …
  • WeakRef.Value: Returns the target object or Nil if the target no longer exists.
Private InternalDict As Dictionary

Sub AddObject(obj As Object)
  Dim wRef As WeakRef
  Dim vObj As Variant
  Dim Hash As Integer
  
  // Is this object already in the Dictionary?
  If HasObject(obj) Then
    // The object is already in the Dictionary
    
  Else
    // Assign the object to a variant
    vObj = obj
    
    // Generate the hash
    Hash = vObj.Hash
    
    // Create the WeakRef
    wRef = New WeakRef(obj)
    
    // Store in the Dictionary
    InternalDict.Value(Hash) = wRef
    
  End If
  
End Sub

Sub Constructor()
  InternalDict = New Dictionary
End Sub

Function HasObject(obj As Object) As Boolean
  Dim rtnResult As Boolean
  Dim vObj As Variant
  Dim Hash As Integer
  Dim wRef As WeakRef
  
  // Set the variant
  vObj = obj
  
  // Get the object hash
  Hash = vObj.Hash()
  
  // Is the hash in the Dictionary?
  If InternalDict.HasKey(Hash) Then
    // Get the WeakRef
    wRef = InternalDict.Value(Hash)
    
    // Does the WeakRef still point to a valid object?
    If wRef.Value <> Nil Then
      
     // Set the return based on if the two objects are infact the same object
     // In theory, according to the docs, because the hash is unique so long as the object lives,
     // the equality test "(obj = wRef.Value)" should always return true because their hashes match.
      rtnResult = (obj = wRef.Value)
      
    Else
      // Hash re-use, the referenced object no longer exists
      rtnResult = False
      
      // You may want to take the opertunity to remove the WeakRef from the Dictionary at this point
      // InternalDict.Remove(Hash)
      
    End If
    
  Else
    // The hash is not in the Dictionary
    rtnResult = False
    
  End If
  
  // Return the result
  Return rtnResult
End Function
  Dim mbStored As New MemoryBlock(0)
  Dim mbNotStored As New MemoryBlock(0)
  Dim wrfd As New WeakRefDict()
  
  wrfd.AddObject(mbStored)
  
  If wrfd.HasObject(mbStored) Then
    MsgBox("Object Located")
  End If
  
  If wrfd.HasObject(mbNotStored) Then
    MsgBox("You should not see this.")
  End If