SetTimer behavior inside classes Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
KuroiLight
Posts: 327
Joined: 12 Apr 2015, 20:24
Contact:

SetTimer behavior inside classes

17 Nov 2017, 22:33

I have a large bit of code that relies on the use of timers in classes and it was working just fine up til recently and I can't really find a cause, but I've been able reproduce it in a reduced test.

Code: Select all

i := new Test()
Loop {
    Sleep, 1000
    ToolTip, % "i.tickCount=" . i.tickCount
}
return

Class Test {
    __New() {
        this.tick := tick := ObjBindMethod(this, "Test.addTick")
        SetTimer, %tick%, 500
    }

    addTick() {
        this.tickCount++
    }
}
Semantically this seems correct based on Example#4 from the SetTimer doc, but addTick never runs.
Any ideas?
Last edited by KuroiLight on 17 Nov 2017, 22:55, edited 1 time in total.
Windows 10, Ryzen 1600, 16GB G.Skill DDR4, 8GB RX 480 | [MyScripts][MySublimeSettings] [Unlicense][MIT License]
01/24/18
[/color]
User avatar
Gio
Posts: 1247
Joined: 30 Sep 2013, 10:54
Location: Brazil

Re: SetTimer behavior inside classes  Topic is solved

17 Nov 2017, 22:55

Hello KuroiLight.

This

Code: Select all

this.tick := tick := ObjBindMethod(this, "Test.addTick")
Should go like

Code: Select all

this.tick := tick := ObjBindMethod(this, "addTick")
And tickCount should be set to 0 at first (null + 1 is NOT 1).

Final code:

Code: Select all

i := new Test()
Loop {
    Sleep, 1000
    ToolTip, % "i.tickCount=" . i.tickCount
}
return

Class Test {

	tickCount := 0

    __New() {
        this.tick := tick := ObjBindMethod(this, "addTick")
        SetTimer, %tick%, 500
    }

    addTick() {
        this.tickCount++
    }
}
Best wishes.
User avatar
KuroiLight
Posts: 327
Joined: 12 Apr 2015, 20:24
Contact:

Re: SetTimer behavior inside classes

17 Nov 2017, 22:57

That did it, Strange that ObjBindMethod takes only the function name and not the class name too, guess I still don't quite understand how classes are implemented. Thanks.
Windows 10, Ryzen 1600, 16GB G.Skill DDR4, 8GB RX 480 | [MyScripts][MySublimeSettings] [Unlicense][MIT License]
01/24/18
[/color]
A_AhkUser
Posts: 1147
Joined: 06 Mar 2017, 16:18
Location: France
Contact:

Re: SetTimer behavior inside classes

17 Nov 2017, 23:38

Hi KuroiLight,

You can also use alternatively:

Code: Select all

this.addTick.bind(this)
(but in this case, as one can see, it is necessary to explicitly pass the first hidden parameter named this, proper to each method, containing generally a reference to the instance).

Also note that, if later you intend to use a __Delete meta-function, you'll have to free stuck references:

Code: Select all

i := new Test()
Loop, 5 {
    Sleep, 1000
    ToolTip, % "i.tickCount=" . i.tickCount
}
i.free() ; so that the line below triggers the __Delete meta-function
i := ""
return

Class Test {
	
	tickCount := 0
	
    __New() {
    tick := this.tick := ObjBindMethod(this, "addTick", "test") ; or this.addTick.bind(this, "test")
        SetTimer % tick, 500
    }
    addTick(__param) {
    this.tickCount++ . A_Space . __param
    }
	free() {
	tick := this.tick
	SetTimer % tick, Off
	SetTimer % tick, Delete
	this.tick := ""
	}
	__Delete() {
	MsgBox % A_ThisFunc
	}
	
}
my scripts
User avatar
KuroiLight
Posts: 327
Joined: 12 Apr 2015, 20:24
Contact:

Re: SetTimer behavior inside classes

18 Nov 2017, 15:19

A_AhkUser wrote: You can also use alternatively:

Code: Select all

this.addTick.bind(this)
Ahk has some confusing rules for references and objects, Wasn't aware you could act directly on the function like that, too used to C# and Lua style objects.
I like ObjBindMethod(this, "functionname") better though, its meaning is more explicit.
A_AhkUser wrote:

Code: Select all

i.free() ; so that the line below triggers the __Delete meta-function
i := ""
Ah, Yea this is something that should be expanded on in the docs, I assumed you could nop an objects properties in __Delete itself and not have to worry about it.

so if I have __Delete like this:

Code: Select all

...
__Delete() {
	prop1 := ""
	return ""
}
...
myObj := myObj.__Delete()
It would technically call __Delete twice?

Code: Select all

global c := 0
i := new Test()
i := i.__Delete()
return

Class Test {
    __Delete() {
        c++
        MsgBox, % c
        return ""
    }
}
it does twice.
but this doesn't at all:

Code: Select all

global c := 0
i := new Test()
i := ""
return

Class Test {
    __New() {
        this.delete_ref := ObjBindMethod(this, "__Delete")
    }

    __Delete() {
        this.delete_ref := ""
        c++
        MsgBox, % c
        return ""
    }
}
I could do this to dispose of objects, seems to work:

Code: Select all

DeleteObject(ByRef object) {
    for i, v in object {
        object[i] := ""
    }
    object := ""
}
Windows 10, Ryzen 1600, 16GB G.Skill DDR4, 8GB RX 480 | [MyScripts][MySublimeSettings] [Unlicense][MIT License]
01/24/18
[/color]
A_AhkUser
Posts: 1147
Joined: 06 Mar 2017, 16:18
Location: France
Contact:

Re: SetTimer behavior inside classes

18 Nov 2017, 21:21

Actually __Delete method can be called like any other one and can even be a buit-in or user-defined function:

Code: Select all

(i:=new Test()).base.__Delete := Func("MsgBox")
i.__Delete()
i := ""
Class Test {
	v := 7
    m(__param) {
	MsgBox % __param
	}
}
MsgBox(this) { ; when Test.MsgBox is called, this is automatically inserted at the beginning of the parameter list  see: https://www.autohotkey.com/docs/Objects.htm#Custom_Prototypes
static __i := 0
MsgBox % this.v . A_Space . ++__i
}
In your second example the __Delete meta-func is not called since the last reference to the instance hasn't been released (this.delete_ref := "") beforehand - compare:

Code: Select all

global c := 0
i := (i:=new Test()).__Delete() ; creates, releases references and sets to an empty string
return

Class Test {
    __New() {
        this.delete_ref := ObjBindMethod(this, "__Delete")
    }
    __Delete() {
        this.delete_ref := ""
        c++
        MsgBox, % c
        return ""
    }
}
That's also the reason why DeleteObject doesn't work in the example below unless you release the function reference set as hotkey label:

Code: Select all

i := new Test()
f := ObjBindMethod(i, "m", "Hello, world!")
Hotkey, !i, % f, on ; ALT+I call the method
f := "" ; however, a reference is still stucked in the Hotkey
return

!x::DeleteObject(i)
^+x::BeforeDeleteObject()

BeforeDeleteObject() {
__f := Func("WinActive") ; a random function
Hotkey, !i, % __f, on
MsgBox, 64,, Now you can delete the object!
}

Class Test {
    m(__param) {
	MsgBox % __param
	}
	__Delete() {
	static __c := 0
	MsgBox % A_ThisFunc . A_Space . ++__c
    }
}

DeleteObject(ByRef __object) {
    for __k, __v in __object {
        __object[__k] := ""
    }
    __object := ""
}
my scripts

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Anput, CrowexBR, Joey5, Rohwedder, Tvlao and 129 guests