Modifying things with Automatic inheritance (Quick HowTo)

Post your Gambas programming questions here.
User avatar
BruceSteers
Posts: 1521
Joined: Thursday 23rd July 2020 5:20pm
Location: Isle of Wight
Contact:

Modifying things with Automatic inheritance (Quick HowTo)

Post by BruceSteers »

A recent discovery of mine that is very very useful is a thing called "Automatic Inheritance"
This is massively useful for simply adding properties to existing classes or to override some of a classes functions.
Also massively useful for backward compatibly as you can auto add or override things (read on for more info)

How you do it...

Lets show you a simple example...
Say you want the Timers in your application to also have a .Tag property.

So in your application make a new class and name it Timer.class
Add the following code to it...
' Gambas class file
Export
Public Const _Properties As String = "*,Tag"
Property Tag As Variant Use $vTag
That's it. Now you will find all your Timer objects also have a Tag property.

Automatic inheritance will automatically make your Timer.class inherit the existing Timer.class as it has the same name.
As Timer can be a virtual IDE object i also added Tag to the _Properties string constant making it visible in the IDE form designer.
[hr] You can go much further than adding new properties/methods to existing classes, you can also override class methods by making your own versions.

Take this example where I want the Timer to have a Stopped event raised if the timer gets disabled. (again the class is just called Timer.class)
' Gambas class file

Export

Property Enabled As Boolean

Event Stopped

Private Sub Enabled_Write(Value As Boolean)

   ' Set the inherited Timer.class Enabled property.
  Super.Enabled = Value

  ' Raise the Stopped event if not enabled
  If Not Value Then Raise Stopped
  
End

Private Function Enabled_Read() As Boolean

  Return Super.Enabled

End

Public Sub Stop()
  
  Me.Enabled = False
  
End
In that example we are overriding the Enabled property and the Stop() method.

Setting Timer.Enabled is now handled by our class, it sets the inherited Timer.Enabled property using Super.Enabled and raises the Stopped event if set to false.
The Stop() method is also overridden to set our own Enabled property and trigger the Stopped event.
[hr] This can also be very useful for backward compatibility.
I had a problem with one of my applications once where i had used the Collection.Keys property not realizing that Keys is new to gambas 3.17. so anyone using an older gambas got an error.

The solution...

I create a class in my application called Collection.class
add the following code..
' Gambas class file

Export 

Property Read Keys As String[]

Private Function Keys_Read() As String[]

  Dim sKeys As New String[]
  For Each Me
    sKeys.Add(Me.Key)
  Next

  Return sKeys

End
Now I am using my own Keys property with Collection.
If an older gambas the Keys property will be added to Collection, if a new gambas then it will be overridden.
[hr] Note:
Properties and methods you override in a class will block the inherited classes properties/methods.
Use the Super keyword to access the inherited class things.
As i have in the second example where i set Super.Enabled, this sets the Enabled property of the inherited Timer.class not my one.

Happy coding.
Bruce
Last edited by BruceSteers on Monday 22nd August 2022 11:02am, edited 2 times in total.
If at first you don't succeed , try doing something differently.
BruceS
User avatar
BruceSteers
Posts: 1521
Joined: Thursday 23rd July 2020 5:20pm
Location: Isle of Wight
Contact:

Re: Modifying things with Automatic inheritance (Quick HowTo)

Post by BruceSteers »

A note regarding backward compatibility.

you could make one of the above examples work more accurately to not just override but use either your added property/method if the users gambas is older and does not have it or using an existing thing if it exists using Try and Error.

eg. (File named Collection.class)
' Gambas class file

Export

Property Read Keys As String[]

Private Function Keys_Read() As String[]

  Dim sKeys As New String[]

  Try sKeys = Super.Keys  ' try to get Keys but don't trigger an error if it fails

  If Error Then  ' Keys did not exist so a bit of DIY.
    For Each Me
      sKeys.Add(Me.Key)
    Next
  Endif

  Return sKeys

End
So in that example we Try to get the Keys property from Super (the inherited Collection.class)
If gambas is 3.17+ then it will use the existing Collection.Keys property.
If an older gambas it will see the error and do it itself.

Similar methods can be used in many cases to either use a classes existing property/method or use your own if the gambas version is missing it.
If at first you don't succeed , try doing something differently.
BruceS
User avatar
thatbruce
Posts: 161
Joined: Saturday 4th September 2021 11:29pm

Re: Modifying things with Automatic inheritance (Quick HowTo)

Post by thatbruce »

Very good. But one observation (of course :twisted: ), AFAIK you cannot override event handlers. If for example you try to override the (self)_Timer event handler then both yours and the native timer events will be called and (AFAIK) there is no way to determine which is called first. Just a caveat.

Your thoughts on this however are probably worth a help howto! You've got the time haven't you :D

Now, just to get serious (and don't call me Shirley!) one thing I am currently having a minor problem is this and your thoughts are welcome. I have used this approach in the past and sometimes I get caught up in a total mind block when I don't realize that I am using a local class override and can't understand why the class does not behave as I expect from the native class. Obscure, yes, but... it would be "nice" to know somehow whether the current instance of an object is the native version, an override in the current project or more importantly an override introduced in some intervening library or component... there are security implications...

Any thoughts?
b (t'other b)
Have you ever noticed that software is never advertised using the adjective "spreadable".
User avatar
BruceSteers
Posts: 1521
Joined: Thursday 23rd July 2020 5:20pm
Location: Isle of Wight
Contact:

Re: Modifying things with Automatic inheritance (Quick HowTo)

Post by BruceSteers »

thatbruce wrote: Tuesday 23rd August 2022 9:37am Very good. But one observation (of course :twisted: ), AFAIK you cannot override event handlers. If for example you try to override the (self)_Timer event handler then both yours and the native timer events will be called and (AFAIK) there is no way to determine which is called first. Just a caveat.

Your thoughts on this however are probably worth a help howto! You've got the time haven't you :D

Now, just to get serious (and don't call me Shirley!) one thing I am currently having a minor problem is this and your thoughts are welcome. I have used this approach in the past and sometimes I get caught up in a total mind block when I don't realize that I am using a local class override and can't understand why the class does not behave as I expect from the native class. Obscure, yes, but... it would be "nice" to know somehow whether the current instance of an object is the native version, an override in the current project or more importantly an override introduced in some intervening library or component... there are security implications...

Any thoughts?
b (t'other b)
Hmm, i though you could override events just fine.

like this (file named Button.class)
' Gambas class file

Export

Private $hObs As Observer

Event MyClick

Public Sub _new()
  
  $hObs = New Observer(Me) As "This"
  
End

Public Sub This_Click()
  
  Stop Event
  Raise MyClick
  
End
that works okay, the button will not fire a Click event as overidden to fire the Myclick event.

I'm not sure i get the issue but my experience is to say try to override as little of the class as possible (just the methods you need)

I've had some troubles where i cannot access the class data needed to override properly. and trying to copy a whole class into a project as an override often get issues not being able to find various attached objects, sometimes importing the whole component is the way to go there.

But sure Events can be overridden with Stop Event and methods/ properties can all be overridden.

Security wise i'm not sure i understand?
maybe you could do some sneaky stuff somehow or other but i guess you could do that without inheritance , the openness of your source will be your undoing ;)

There probably is a way to see if a class has overrides (Ben would be the guy to ask about the easiest way to do that)
maybe by checking out the object/class hierarchy ?

Respects
English Bruce
If at first you don't succeed , try doing something differently.
BruceS
User avatar
BruceSteers
Posts: 1521
Joined: Thursday 23rd July 2020 5:20pm
Location: Isle of Wight
Contact:

Re: Modifying things with Automatic inheritance (Quick HowTo)

Post by BruceSteers »

thatbruce wrote: Tuesday 23rd August 2022 9:37am Very good. But one observation (of course :twisted: ), AFAIK you cannot override event handlers. If for example you try to override the (self)_Timer event handler then both yours and the native timer events will be called and (AFAIK) there is no way to determine which is called first. Just a caveat.
okay i had a play and it seems the Timer_Timer() event is a good example there of what not to override. you cannot so much "override" the timer event because if you stop the event the inherited timer misses it's trigger and does not trigger again? odd

But you CAN intercept the Timer_Timer() event and do stuff in it like raise other events, set properties, etc but gotta let it trigger it's internal event :)
' Gambas class file

Export

Private $hObs As Observer

Private $TriggerCount As Integer

Event ImTriggered(Count As Integer)

Public Sub _new()
  
  $hObs = New Observer(Me) As "This"
  
End

Public Sub This_Timer()

  Inc $TriggerCount
  Raise ImTriggered($TriggerCount)

End
If you use that Timer.class and use both the Timer and MyTimer event handlers then you find the intercept MyTimer triggers before Timer
' Gambas class file

Public Sub Timer1_Timer()

  Print "timer event"

End

Public Sub Timer1_ImTriggered(count As Integer)

  Print "trigger event No";; count

End
produces this...

Code: Select all

trigger event No 1
timer event
trigger event No 2
timer event
trigger event No 3
timer event

Respects.
If at first you don't succeed , try doing something differently.
BruceS
User avatar
PJBlack
Posts: 184
Joined: Tuesday 9th June 2020 10:26pm
Location: Florstadt, Hessen, Germany

Re: Modifying things with Automatic inheritance (Quick HowTo)

Post by PJBlack »

I overload the "TextLabel" class with my own properties. What works so far programmatically, but in the IDE I can not enter new values.
' Gambas class file

Export

Public Const _Properties As String = "*,IsHeader,IsList"

Property IsHeader As Boolean
Private $IsHeader As Boolean = False

Property IsList As Boolean
Private $IsList As Boolean = False

Private Function IsHeader_Read() As Boolean

    Return $IsHeader

End

Private Sub IsHeader_Write(Value As Boolean)

    $IsHeader = Value

End

Private Function IsList_Read() As Boolean

    Return $IsList

End

Private Sub IsList_Write(Value As Boolean)

    $IsList = Value

End

What am I doing wrong?
User avatar
BruceSteers
Posts: 1521
Joined: Thursday 23rd July 2020 5:20pm
Location: Isle of Wight
Contact:

Re: Modifying things with Automatic inheritance (Quick HowTo)

Post by BruceSteers »

The code looks good , have you presses the "compile all" button?
If at first you don't succeed , try doing something differently.
BruceS
User avatar
BruceSteers
Posts: 1521
Joined: Thursday 23rd July 2020 5:20pm
Location: Isle of Wight
Contact:

Re: Modifying things with Automatic inheritance (Quick HowTo)

Post by BruceSteers »

I tried your code and got the variables in the IDE but could not change them.

Seems like a bug

If you rename the class to TextLabel2.class and add "Inherits TextLabel" then it all works as expected.
If at first you don't succeed , try doing something differently.
BruceS
User avatar
PJBlack
Posts: 184
Joined: Tuesday 9th June 2020 10:26pm
Location: Florstadt, Hessen, Germany

Re: Modifying things with Automatic inheritance (Quick HowTo)

Post by PJBlack »

BruceSteers wrote: Saturday 25th March 2023 3:52pm I tried your code and got the variables in the IDE but could not change them.
same here ...
BruceSteers wrote: Saturday 25th March 2023 3:52pm If you rename the class to TextLabel2.class and add "Inherits TextLabel" then it all works as expected.
I know ... but thats nt what I want
BruceSteers wrote: Saturday 25th March 2023 3:52pm Seems like a bug
:D ;) then fix it :P
User avatar
BruceSteers
Posts: 1521
Joined: Thursday 23rd July 2020 5:20pm
Location: Isle of Wight
Contact:

Re: Modifying things with Automatic inheritance (Quick HowTo)

Post by BruceSteers »

PJBlack wrote: Saturday 25th March 2023 3:57pm
BruceSteers wrote: Saturday 25th March 2023 3:52pm I tried your code and got the variables in the IDE but could not change them.
same here ...
BruceSteers wrote: Saturday 25th March 2023 3:52pm If you rename the class to TextLabel2.class and add "Inherits TextLabel" then it all works as expected.
I know ... but thats nt what I want
BruceSteers wrote: Saturday 25th March 2023 3:52pm Seems like a bug
:D ;) then fix it :P

Haha

I have asked the experts for a reason as to why it does not work........
If at first you don't succeed , try doing something differently.
BruceS
Post Reply