The order of creating classes (OOP)

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
murataygun
Posts: 104
Joined: 07 Aug 2015, 15:53

The order of creating classes (OOP)

23 Sep 2022, 10:35

Hi :wave:

- Controller class controls common tasks and options.
- Telemetri is a class which gets new options from API

What im trying to do is;

when telemetri gets new Interval value, change the interval of the timer.

Both classes has referances to each other. What is the correct order to create them? I took controller up and down in lines.

So if two classes has referances to eachother. Which order should i create them?

Thank you very much.

Code: Select all


#Persistent
global Telemetri := new Telemetri_class()
global Controller := new Controller_class()

class Controller_class {

    ;Main options and functions here.
    __New() {

        SetTimer, % Telemetri.Tele(), 20000
    }

    changeTelemetriInterval(_interval) {
        SetTimer, % Telemetri.Tele(), % _interval
    }
}
class Telemetri_class {
    ;Do some API CALLS
    ;get new interval value
    __New() {
        ;Controller.changeTelemetriInterval(60000)
    }
    Tele() {
        MsgBox, Telemetri is in action
        ;new data arrived which is 60000
        Controller.changeTelemetriInterval(60000)
    }
}
iPhilip
Posts: 827
Joined: 02 Oct 2013, 12:21

Re: The order of creating classes (OOP)

23 Sep 2022, 13:31

@murataygun, It shouldn't matter in which order you instantiate the classes. What I did notice is a few critical errors in your code: a) the Label parameter of the SetTimer command is neither a string or a function object and b) your code contains circular references. The code below fixes the SetTimer issues but not the circular references. See the comments.

Code: Select all

#Persistent
global Telemetri := new Telemetri_class()
global Controller := new Controller_class()

class Controller_class {

    ;Main options and functions here.
    __New() {
        FuncObj := ObjBindMethod(Telemetri, "Tele")  ; This requires that the Telemetri instance exists when the Controller instance is created.
        SetTimer, % FuncObj, 20000
    }

    changeTelemetriInterval(_interval) {
        FuncObj := ObjBindMethod(Telemetri, "Tele")  ; This requires that the Telemetri instance exists when the Controller instance is created.
        SetTimer, % FuncObj, % _interval
    }
}
class Telemetri_class {
    ;Do some API CALLS
    ;get new interval value
    __New() {
        ;Controller.changeTelemetriInterval(60000)  ; This requires that the Controller instance exists when the Telemetri instance is created.
    }
    Tele() {
        MsgBox, Telemetri is in action
        ;new data arrived which is 60000
        Controller.changeTelemetriInterval(60000)  ; This requires that the Controller instance exists.
    }
}
The above circular references go away if you use the class object in place of the instance object. See the code below.

Code: Select all

#Persistent
; The instances don't have to be declared as global variables
Controller := new Controller_class()
Telemetri := new Telemetri_class()  ; You may not need to instantiate this class.

class Controller_class {

    ;Main options and functions here.
    __New() {
        FuncObj := ObjBindMethod(Telemetri_class, "Tele")
        SetTimer, % FuncObj, 20000
    }

    changeTelemetriInterval(_interval) {
        FuncObj := ObjBindMethod(Telemetri_class, "Tele")
        SetTimer, % FuncObj, % _interval
    }
}
class Telemetri_class {
    ;Do some API CALLS
    ;get new interval value
    __New() {
        ;Controller_class.changeTelemetriInterval(60000)
    }
    Tele() {
        MsgBox, Telemetri is in action
        ;new data arrived which is 60000
        Controller_class.changeTelemetriInterval(60000)
    }
}
I hope this helps.
Windows 10 Pro (64 bit) - AutoHotkey v2.0+ (Unicode 64-bit)
murataygun
Posts: 104
Joined: 07 Aug 2015, 15:53

Re: The order of creating classes (OOP)

23 Sep 2022, 14:43

iPhilip wrote:
23 Sep 2022, 13:31
@murataygun, It shouldn't matter in which order you instantiate the classes. What I did notice is a few critical errors in your code: a) the Label parameter of the SetTimer command is neither a string or a function object and b) your code contains circular references. The code below fixes the SetTimer issues but not the circular references. See the comments.
Thank you Philip,
It seems like timer is not replacing with new interval but creating new timers. See Gif. I builds up message boxses.

Image
Lepes
Posts: 141
Joined: 06 May 2021, 07:32
Location: Spain

Re: The order of creating classes (OOP)

23 Sep 2022, 15:29

IMO:
- if you have circular references, then it is a bad design. You should change it.
- Controller class shouldn't change anything of another class, although it could call some Telemetri method to change its values.
- If Controller has many Telemetri instances to control, then Controller could have an array of telemetri objects, so controller could call any method.
- On controller class you have a method named "changeTelemetriInterval", that says that this method should be on Telemetri class, not in Controller class, bottom line.

this is pseudocode:

Code: Select all

#Persistent
global Controller := new Controller_class()
global Telemetri := new Telemetri_class(Controller)
Controller.Add(Telemetri)  ; creation order solved!!!  That's the way baby.

class Controller_class {
     Teles = []
    ;Main options and functions here.
    __New() {

    }
    Add( ATele){
      this.Teles.push(ATele)
      ; now on Controller class you can execute something like "this.Teles[1].changeInterval(60000)  and Controller is not modifying Telemetri properties. It is Telemetri who changes its own properties, that's the OOP point
    }
}
class Telemetri_class {
    ;Do some API CALLS
    ;get new interval value
    __New(AController) {
	this.TheController := AController ; you can hold here the controller of this Telemetri, if you need.
    }
    Tele() {
        MsgBox, Telemetri is in action
        ;new data arrived which is 60000
        this.changeInterval(60000) 
    }
    changeInterval(_interval) {
	SetTimer,% FuncObj, Off   ; important to disable the previous timer, I didn't test if a current disabled timer would be executed when interval expire. maybe!!
        FuncObj := ObjBindMethod(Telemetri, "Tele")  
        SetTimer, % FuncObj, % _interval
    }
    
}
Now there are no circular references on class design. You still could do circular references on runtime:

Code: Select all

Telemetri.TheController.Teles[1].changeInterval(3000)  ; this line is also called brainFucker  :XD  . If you type this, you need a rest!!
To avoid this runtime circular references, "Teles" property should be private (I don't know how to do it on AutoHotkey, sorry)
murataygun
Posts: 104
Joined: 07 Aug 2015, 15:53

Re: The order of creating classes (OOP)

23 Sep 2022, 16:12

Lepes wrote:
23 Sep 2022, 15:29
IMO:
- if you have circular references, then it is a bad design. You should change it.
- Controller class shouldn't change anything of another class, although it could call some Telemetri method to change its values.
- If Controller has many Telemetri instances to control, then Controller could have an array of telemetri objects, so controller could call any method.
- On controller class you have a method named "changeTelemetriInterval", that says that this method should be on Telemetri class, not in Controller class, bottom line.
Thank you. Good advices.
I had just one Telemetri to control. My controller class controls lost of things. Maybe i dont need it. I took everything in Telemetri class and i'm now happy. Maybe i should take an OOP course btw.

This code on docs helped me alot.

Code: Select all

counter := new SecondCounter
counter.Start()
Sleep 5000
counter.Stop()
Sleep 2000

; An example class for counting the seconds...
class SecondCounter {
    __New() {
        this.interval := 1000
        this.count := 0
        ; Tick() has an implicit parameter "this" which is a reference to
        ; the object, so we need to create a function which encapsulates
        ; "this" and the method to call:
        this.timer := ObjBindMethod(this, "Tick")
    }
    Start() {
        ; Known limitation: SetTimer requires a plain variable reference.
        timer := this.timer
        SetTimer % timer, % this.interval
        ToolTip % "Counter started"
    }
    Stop() {
        ; To turn off the timer, we must pass the same object as before:
        timer := this.timer
        SetTimer % timer, Off
        ToolTip % "Counter stopped at " this.count
    }
    ; In this example, the timer calls this method:
    Tick() {
        ToolTip % ++this.count
    }
}

iPhilip
Posts: 827
Joined: 02 Oct 2013, 12:21

Re: The order of creating classes (OOP)

23 Sep 2022, 16:44

murataygun wrote:
23 Sep 2022, 16:12
This code on docs helped me alot.
Great! You might also want to take a look at this simplified version of the SecondCounter class.
Windows 10 Pro (64 bit) - AutoHotkey v2.0+ (Unicode 64-bit)

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: kaka2 and 140 guests