"AssociatedObject" key through different variable

Mac OSX specific forum
mestnyi
Addict
Addict
Posts: 1098
Joined: Mon Nov 25, 2013 6:41 am

"AssociatedObject" key through different variable

Post by mestnyi »

Code: Select all

ImportC ""
  objc_setAssociatedObject( object,    ; Any
                            key.s,     ; UnsafeRawPointer,
                            value,     ; Any?,
                            policy )   ; objc_AssociationPolicy 
  
  objc_getAssociatedObject( object,    ; Any
                            key.s )    ; UnsafeRawPointer
EndImport

If OpenWindow(0, 0, 0, 300, 300, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget)
  Define key.s = "___data"
  Define key1.s = key ; "___data"
  
  objc_setAssociatedObject_( WindowID(0), key, 12345, 0 ) 
  Debug objc_getAssociatedObject_( WindowID(0), key1 ) 
  
  Repeat
    Event = WaitWindowEvent()
  Until Event = #PB_Event_CloseWindow
EndIf     
mestnyi
Addict
Addict
Posts: 1098
Joined: Mon Nov 25, 2013 6:41 am

Re: "AssociatedObject" key through different variable

Post by mestnyi »

does anyone know why this is happening?
User avatar
fsw
Addict
Addict
Posts: 1603
Joined: Tue Apr 29, 2003 9:18 pm
Location: North by Northwest

Re: "AssociatedObject" key through different variable

Post by fsw »

Not sure why, but I found this:
https://nshipster.com/associated-objects/

And it says that the keys should be constants:
It is often recommended that they key be a static char—or better yet, the pointer to one. Basically, an arbitrary value that is guaranteed to be constant, unique, and scoped for use within getters and setters:
If the key is a variable and it is copied (as in your case) it is not unique anymore, is it?

The AssociatedObject functions uses the exact memory location (pointer) of the variable.

Code: Select all

  key.s,     ; UnsafeRawPointer,
The proof is in the pudding:
Using constants instead of variables works even when a constant is copied:

Code: Select all

#key = "___data"
#key2 = #key
and later using:

Code: Select all

  Debug objc_getAssociatedObject_( WindowID(0), #key ) 
  Debug objc_getAssociatedObject_( WindowID(0), #key2 ) 
  Debug objc_getAssociatedObject_( WindowID(0), "___data" ) 
shows the same results.

#key and #key2 seem to hold the pointer to "___data" because the outputs are the same.

Strangely enough, the second literal string "___data" in the objc_getAssociatedObject_ function call works as well, even though the memory location should differ from the first literal string of "___data" (while defining #key = "___data").
Maybe the PB compiler is smart enough and compares literal strings with already used literal strings and if it finds the same literal string it uses the pointer of the original literal string, instead of storing the same literal string twice.

Interesting stuff...

I am to provide the public with beneficial shocks.
Alfred Hitshock
mestnyi
Addict
Addict
Posts: 1098
Joined: Mon Nov 25, 2013 6:41 am

Re: "AssociatedObject" key through different variable

Post by mestnyi »

I wanted to use like this.
It didn't work, but what surprises me is if I add this line "AllocateStructure(String)" anywhere, it starts working. :shock:
or when I assign "key" to a structure like this "Protected *key.String = @key"

Code: Select all

AllocateStructure(String) ;1 uncomment to see work - why??????????

DeclareModule Associated
  EnableExplicit
  Declare Get( object.i, key.s )
  Declare Remove( object.i, key.s )
  Declare Set( object.i, key.s, value.i )
EndDeclareModule

Module Associated
    CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
    #OBJC_ASSOCIATION_ASSIGN = 0
    #OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1
    #OBJC_ASSOCIATION_COPY_NONATOMIC = 3
    #OBJC_ASSOCIATION_RETAIN = 769
    #OBJC_ASSOCIATION_COPY = 771
  CompilerEndIf
  
  Procedure Get( object.i, key.s )
    ;Protected *key.String = @key ;2 uncomment to see work
    
    CompilerSelect #PB_Compiler_OS 
      CompilerCase #PB_OS_MacOS
        ProcedureReturn objc_getAssociatedObject_( object, key ) 
        
      CompilerCase #PB_OS_Windows
        ProcedureReturn GetProp_( object, key )
        
    CompilerEndSelect                                                                  
  EndProcedure
  
  Procedure Remove( object.i, key.s )
    CompilerSelect #PB_Compiler_OS 
      CompilerCase #PB_OS_MacOS
        objc_setAssociatedObject_( object, key, #Null, #OBJC_ASSOCIATION_ASSIGN ) 
        ; objc_removeAssociatedObjects_(object )
        
      CompilerCase #PB_OS_Windows
        RemoveProp_( object, key )
        
    CompilerEndSelect                                                                    
  EndProcedure
  
  Procedure Set( object.i, key.s, value.i )
    CompilerSelect #PB_Compiler_OS 
      CompilerCase #PB_OS_MacOS
        objc_setAssociatedObject_( object, key, value, #OBJC_ASSOCIATION_ASSIGN ) 
        
      CompilerCase #PB_OS_Windows
        SetProp_(object, key, value )
        
    CompilerEndSelect                                                                   
  EndProcedure
EndModule

CompilerIf #PB_Compiler_IsMainFile
  CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
    If OpenWindow(0, 0, 0, 300, 300, "Resize me !", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget)
      Define key.s = "___data"
      Define key1.s = key ; "___data"
      ;Define *key.String = @key1
      
;       objc_setAssociatedObject_( WindowID(0), key, 12345, 0 ) 
;       Debug objc_getAssociatedObject_( WindowID(0), key1 ) 
      
      Associated::Set( WindowID(0), "___data", 12345)
      Debug Associated::Get( WindowID(0), "___data")
      
      Repeat
        Event = WaitWindowEvent()
      Until Event = #PB_Event_CloseWindow
    EndIf 
  CompilerEndIf
CompilerEndIf
  
User avatar
fsw
Addict
Addict
Posts: 1603
Joined: Tue Apr 29, 2003 9:18 pm
Location: North by Northwest

Re: "AssociatedObject" key through different variable

Post by fsw »

Something is goofy...

This works as well even though it shouldn't:

Code: Select all

      Define key.s = "___data"
      Define key1.s = key ; "___data"

      Associated::Set( WindowID(0), "___data", 12345)
      Debug Associated::Get( WindowID(0), "___data")
      Debug Associated::Get( WindowID(0), key)
      Debug Associated::Get( WindowID(0), key1)
Weird!

Even more weird:

Code: Select all

      Define key.s = "___data"
      Define key1.s = key ; "___data"

      Associated::Set( WindowID(0), "___banana", 12345)
      Debug Associated::Get( WindowID(0), key)
      Debug Associated::Get( WindowID(0), key1)
      Debug Associated::Get( WindowID(0), "___d")
      Debug Associated::Get( WindowID(0), "___da")
      Debug Associated::Get( WindowID(0), "___dat")
      Debug Associated::Get( WindowID(0), "___data")
:shock:

I am to provide the public with beneficial shocks.
Alfred Hitshock
mestnyi
Addict
Addict
Posts: 1098
Joined: Mon Nov 25, 2013 6:41 am

Re: "AssociatedObject" key through different variable

Post by mestnyi »

amazing things really happen :shock:
Well at least it works.

Code: Select all

DeclareModule Associated
  Declare Get( object.i, *key.String )
  Declare Remove( object.i, *key.String )
  Declare Set( object.i, *key.String, value.i )
EndDeclareModule

Module Associated
  CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
    #OBJC_ASSOCIATION_ASSIGN = 0
    #OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1
    #OBJC_ASSOCIATION_COPY_NONATOMIC = 3
    #OBJC_ASSOCIATION_RETAIN = 769
    #OBJC_ASSOCIATION_COPY = 771
  CompilerEndIf
  
  Procedure Get( object.i, *key.String )
    CompilerSelect #PB_Compiler_OS 
      CompilerCase #PB_OS_MacOS
        ProcedureReturn objc_getAssociatedObject_( object, *key\s ) 
        
      CompilerCase #PB_OS_Windows
        ProcedureReturn GetProp_( object, *key\s )
        
    CompilerEndSelect                                                                  
  EndProcedure
  
  Procedure Remove( object.i, *key.String )
    CompilerSelect #PB_Compiler_OS 
      CompilerCase #PB_OS_MacOS
        objc_setAssociatedObject_( object, *key\s, #Null, #OBJC_ASSOCIATION_ASSIGN ) 
        ; objc_removeAssociatedObjects_(object )
        
      CompilerCase #PB_OS_Windows
        RemoveProp_( object, *key\s )
        
    CompilerEndSelect                                                                    
  EndProcedure
  
  Procedure Set( object.i, *key.String, value.i )
    CompilerSelect #PB_Compiler_OS 
      CompilerCase #PB_OS_MacOS
        objc_setAssociatedObject_( object, *key\s, value, #OBJC_ASSOCIATION_ASSIGN ) 
        
      CompilerCase #PB_OS_Windows
        SetProp_(object, *key\s, value )
        
    CompilerEndSelect                                                                   
  EndProcedure
EndModule

CompilerIf #PB_Compiler_IsMainFile
  CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
    If OpenWindow(0, 0, 0, 300, 300, "Resize me !", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget)
;       Define key.s = "___data"
;       Define key1.s = key ; "___data"
;       
; ;       objc_setAssociatedObject_( WindowID(0), key, 12345, 0 ) 
; ;       Debug objc_getAssociatedObject_( WindowID(0), key1 ) 
;       
;       Associated::Set( WindowID(0), @"___data", 12345)
;       Debug Associated::Get( WindowID(0), @"___data")
;       Associated::Remove( WindowID(0), @"___data")
;       Debug Associated::Get( WindowID(0), @"___data")
      
      Define key.s = "___data"
      Define key1.s = key ; "___data"

      Associated::Set( WindowID(0), @"___banana", 12345)
      Debug Associated::Get( WindowID(0), @key)
      Debug Associated::Get( WindowID(0), @key1)
      Debug Associated::Get( WindowID(0), @"___d")
      Debug Associated::Get( WindowID(0), @"___da")
      Debug Associated::Get( WindowID(0), @"___dat")
      Debug Associated::Get( WindowID(0), @"___data")
      Debug Associated::Get( WindowID(0), @"___banana")
      
      Repeat
        Event = WaitWindowEvent()
      Until Event = #PB_Event_CloseWindow
    EndIf 
  CompilerEndIf
CompilerEndIf
mestnyi
Addict
Addict
Posts: 1098
Joined: Mon Nov 25, 2013 6:41 am

Re: "AssociatedObject" key through different variable

Post by mestnyi »

no, that doesn't work either.
it turns out the key should not be longer than 4 characters :shock:

Code: Select all

      Associated::Set( WindowID(0), @"___data", 12345)
      Associated::Set( WindowID(0), @"___data2", 54321)
      Debug Associated::Get( WindowID(0), @"___data")
      Debug Associated::Get( WindowID(0), @"___data2")
mestnyi
Addict
Addict
Posts: 1098
Joined: Mon Nov 25, 2013 6:41 am

Re: "AssociatedObject" key through different variable

Post by mestnyi »

he did not need a line :shock:

Code: Select all

CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
    If OpenWindow(0, 0, 0, 300, 300, "Resize me !", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget)
      Define key3 = 1234566788
      Define key4 = key3
      
      objc_setAssociatedObject_( WindowID(0), 123456789, 12345, 0 ) 
      Debug objc_getAssociatedObject_( WindowID(0), 123456789 ) 
      
      objc_setAssociatedObject_( WindowID(0), key3, 12345, 0 ) 
      Debug objc_getAssociatedObject_( WindowID(0), key4 ) 
      
      Repeat
        Event = WaitWindowEvent()
      Until Event = #PB_Event_CloseWindow
    EndIf 
  CompilerEndIf
User avatar
mk-soft
Always Here
Always Here
Posts: 6246
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: "AssociatedObject" key through different variable

Post by mk-soft »

Why not use maps ...

Update
- Bugfix

Code: Select all

DeclareModule Associated
  Declare Get( object.i, key.s )
  Declare Set( object.i, key.s, value.i )
  Declare Remove( object.i, key.s )
  Declare Release( object.i )
EndDeclareModule

Module Associated
  
  Structure udtAssociatedObject
    Map key.i()
  EndStructure
  
  Global NewMap mapAssociatedObject.udtAssociatedObject()
  
  Procedure Get( object.i, key.s )
    If FindMapElement(mapAssociatedObject(), Str(object))
      If FindMapElement(mapAssociatedObject()\key(), key)
        ProcedureReturn mapAssociatedObject()\key()
      EndIf
    EndIf
  EndProcedure
  
  Procedure Set( object.i, key.s, value.i )
    If Not FindMapElement(mapAssociatedObject(), Str(object))
      AddMapElement(mapAssociatedObject(), Str( object))
    EndIf
    If AddMapElement(mapAssociatedObject()\key(), key)
      mapAssociatedObject()\key() = value
      ProcedureReturn #True
    EndIf
    ProcedureReturn #False
  EndProcedure
  
  Procedure Remove( object.i, key.s )
    If FindMapElement(mapAssociatedObject(), Str(object))
      If FindMapElement(mapAssociatedObject()\key(), key)
        DeleteMapElement(mapAssociatedObject()\key())
      EndIf
    EndIf
  EndProcedure
  
  Procedure Release( object.i )
    If FindMapElement(mapAssociatedObject(), Str(object))
      DeleteMapElement(mapAssociatedObject())
    EndIf
  EndProcedure
  
  
EndModule

CompilerIf #PB_Compiler_IsMainFile
  CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
    If OpenWindow(0, 0, 0, 300, 300, "Resize me !", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget)
      
      Define key.s = "___data"
      Define key1.s = key ; "___data"

      Associated::Set( WindowID(0), "___banana", 12345)
      Associated::Set( WindowID(0), key1, 100)
      Debug Associated::Get( WindowID(0), key)
      Debug Associated::Get( WindowID(0), key1)
      Debug Associated::Get( WindowID(0), "___d")
      Debug Associated::Get( WindowID(0), "___da")
      Debug Associated::Get( WindowID(0), "___dat")
      Debug Associated::Get( WindowID(0), "___data")
      Debug Associated::Get( WindowID(0), "___banana")
      
      Repeat
        Event = WaitWindowEvent()
      Until Event = #PB_Event_CloseWindow
    EndIf 
  CompilerEndIf
CompilerEndIf
Last edited by mk-soft on Sun Oct 16, 2022 11:27 pm, edited 1 time in total.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
mestnyi
Addict
Addict
Posts: 1098
Joined: Mon Nov 25, 2013 6:41 am

Re: "AssociatedObject" key through different variable

Post by mestnyi »

mk-soft wrote: Sat Oct 15, 2022 10:27 am Why not use maps ...
I thought it would be better and more reliable :(
And the memory will be less.
User avatar
fsw
Addict
Addict
Posts: 1603
Joined: Tue Apr 29, 2003 9:18 pm
Location: North by Northwest

Re: "AssociatedObject" key through different variable

Post by fsw »

@mk-soft:
This is the output on my M1 Mac:
100
100
0
0
0
100
0
but it should be:
100
100
0
0
0
100
12345
@mestnyi
Further testing with your first code shows that it works perfectly as long as real constants or literal strings are used.

I am to provide the public with beneficial shocks.
Alfred Hitshock
User avatar
mk-soft
Always Here
Always Here
Posts: 6246
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: "AssociatedObject" key through different variable

Post by mk-soft »

My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Post Reply