Adding Properties using Extend

I sometimes come across a need or desire to add properties to an existing class, like you can add methods using Extend. Subclassing doesn’t work as the class already exists as an output from someone else’s routine.

I thought that using Static within the extend methods might do it, but it appears that Static works as if it is a shared property - and all the class instances access the same value.

So then I tried adding a dictionary to a module of methods, each with a Getter and Setter, along the following lines:

[code]Public Sub IntegerProperty(extends cnv as canvas, assigns val as integer)
//this is setter

//make sure dictionary exists
If di = Nil Then di = New Dictionary

//get dictionary for this method
Dim di2 As dictionary = di.Lookup(CurrentMethodName, Nil)

//ensure dictionary exists
If di2 = Nil Then
di2 = New Dictionary
//add it to the base dictionary
di.value(CurrentMethodName) = di2
End If

//assign the value
di2.value(cnv) = Val

End Sub

Public Function IntegerProperty(extends cnv as canvas) as Integer
//this is getter
Dim defaultValue As Integer = 0

//make sure dictionary exists
If di = Nil Then Return defaultValue
//get dictionary for this method
Dim di2 As dictionary = di.Lookup(CurrentMethodName, Nil)

//if no dicionary, return default
If di2 = Nil Then Return defaultValue

//get the value from the dictionary - could be any value or class
Return di2.Lookup(cnv, defaultValue)

End Function

Public Sub IntegerProperty(extends cnv as canvas, destruct as boolean)
//this Is destructor - called by destruct for the extended class
//not sure how to call this - needs something that calls the destructor

//get the dictionary
If di = Nil Then Return

//get dictionary for this method and remove it
Dim di2 As dictionary = di.lookup(CurrentMethodName, Nil)
If di2 = Nil Then Return
di2.Remove(cnv)

Return

End Sub
[/code]

These seem to work fine, with one exception, how to remove the associated value from the dictionary when the associated super class is destructed. Does anyone have a better way of doing this and a way of removing the property values on destruction?

I don’t follow you here. A subclass would seem to be well suited for this.

A Destructor method on a custom subclass would also seem to be well suited.

if it is someone else class (xojo for example) , you don’t always have access to subclass it. an extension is better suited.

You can subclass Xojo’s classes. Are you talking about encrypted or plugin classes? Because now that I think of it I’m not sure if they behave differently.

This is a module I named RectControlTagModule meant to add a Tag property to RectControl class.
It has a sort of garbage collection to remove dead references.

Just create a module and paste the following properties and methods.
Then you can adapt it to your needs.

Private Property tags as Pair()
Public Function Tag(extends c as RectControl) as Variant
  //the main purpose of the pragma is to prevent a context switch.
  #pragma disableBackgroundTasks
  
  Tags = RemoveDeadRefs(Tags)
  
  dim tagValue as Variant = nil
  for each p as Pair in Tags
    dim w as WeakRef = p.Left
    if w.Value = c then
      tagValue = p.Right
      exit
    end if
  next
  
  return tagValue
End Function
Public Sub Tag(extends c as RectControl, assigns value as Variant)
  //the main purpose of the pragma is to prevent a context switch.
  #pragma disableBackgroundTasks
  
  Tags = RemoveDeadRefs(Tags)
  
  dim index as Integer = -1
  for i as Integer = 0 to UBound(Tags)
    dim w as WeakRef = Tags(i).Left
    if w.Value = c then
      index = i
      exit
    end if
  next
  
  if index > -1 then
    Tags(index) = new WeakRef(c) : value
  else
    Tags.Append new WeakRef(c) : value
  end if
End Sub
Private Function RemoveDeadRefs(tagList() as Pair) as Pair()
  //the main purpose of the pragma is to prevent a context switch.
  #pragma disableBackgroundTasks
  
  dim newList() as Pair
  
  for each p as Pair in tagList
    dim w as WeakRef = p.Left
    if w.Value <> nil then
      newList.Append p
    end if
  next
  
  return newList
End Function

I think Massimo got the gist of this. You want to add a property to a superclass so all its children inherit it automatically, but, like RectControl in his example, you don’t have direct access to modify the superclass. His example is the way to do it.

Changes I might make: use a Semaphore instead of shutting off background tasks and a Timer to call RemoveDeadRefs instead of doing it on every set/get. (The ability to assign a Destructor to the superclass would be ideal, but since you can’t…)

I do the same as Massimo, essentially. There is another way in Cocoa but it is obviously macOS only.

If you want to store several “properties”, just use Massimo’s Tag method to store a Dictionary which contains all the properties you want.

[quote=418691:@Kem Tekinay]I think Massimo got the gist of this. You want to add a property to a superclass so all its children inherit it automatically, but, like RectControl in his example, you don’t have direct access to modify the superclass. His example is the way to do it.

Changes I might make: use a Semaphore instead of shutting off background tasks and a Timer to call RemoveDeadRefs instead of doing it on every set/get. (The ability to assign a Destructor to the superclass would be ideal, but since you can’t…)[/quote]
I don’t have the vocabulary to explain it clearly.
hopefully we have Kem !

@Jean-Yves Pochez — Don’t worry, Kem is the representative for Gilets Jaunes !! :slight_smile:

Thank you all. You’ve confirmed I was on the right track and not completely bonkers. I’ll stick with the dictionary version so can add multiple properties for multiple classes all in the same dictionary. The addition of weakRef is what I needed I think for clearing out the destructed classes, plus a timer for its occasional purging.