Extending pre-existing classes

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
Descolada
Posts: 1098
Joined: 23 Dec 2021, 02:30

Extending pre-existing classes

Post by Descolada » 16 May 2022, 06:59

Hello,
Is it possible to add methods to an existing class with an external library? I am trying to develop a library to extend an existing library that has some classes, for which I would like to add extra methods. For example, suppose there is a pre-existing Testlibrary with a class Test:

Code: Select all

class Test {
	FirstFunc(var) {
		MsgBox, This is function 1 called with variable %var%
	}
}
Now I want to add a new function SecondFunc to be used with the Test class.
[code]SecondFunc(var) {
	MsgBox, Some other function called with variable %var%
}
I do not want to fork Testlibrary to add SecondFunc, but instead I want to create Testlibrary_extended that can be used along with Testlibrary:

Code: Select all

#include <Testlibrary>
#include <Testlibrary_extended>
nt := new Test
nt.FirstFunc("first function call")
nt.SecondFunc("second function call")
Currently I am adding using the __New method inside class Test to dynamically check if SecondFunc exists inside a Test_extended class, and if yes then I add it with the Func function. But this method also relies on modifying Library1, which I do not want to do.
One other way I have considered is adding a for loop to the top of Testlibrary_extended, which would add all methods inside a Test_extended class to the Test class. The trouble with this way is that it relies on the code being executed in the main part of the script, which means the #include must be at the top of the code to properly work.

Is there some better way to solve this? Ideally something like this:

Code: Select all

class Test extends Test {
	SecondFunc(var) {
		MsgBox, Some other function called with variable %var%
	}
}

User avatar
Chunjee
Posts: 1400
Joined: 18 Apr 2014, 19:05
Contact:

Re: Extending pre-existing classes

Post by Chunjee » 16 May 2022, 08:06

I do not know exactly why this works. But you may extend the external library methods by adding two classes together:

Code: Select all

class Test {
	FirstFunc(var) {
		MsgBox, This is function 1 called with variable %var%
	}
}
class addonFunctions {
	SecondFunc(var) {
		MsgBox, Some other function called with variable %var%
	}
}

Test.base := addonFunctions
Test.SecondFunc("hello")
; => "Some other function called with variable hello"
It does require that those addon functions be inside another semi-unused class.

I think someone helped me on Discord but here is the post where I also asked (and answered): viewtopic.php?f=7&t=6033&p=450197#p450197



This is how biga.ahk plugins work; such as seen here: https://github.com/Chunjee/frequencies_bigaplugin.ahk

Code: Select all

#Include biga.ahk\export.ahk
#Include frequencies_bigaplugin.ahk\export.ahk

A := new biga()
A.frequencies([1, 1, 3, 3, 4, 4, 5, 5, 8, 8])
; => {1: 2, 3: 2, 4: 2, 5: 2, 8: 2}

Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: Extending pre-existing classes

Post by Helgef » 16 May 2022, 09:33

You cannot continue the class definition.
I am trying to develop a library to extend an existing library that has some classes, for which I would like to add extra methods
For that purpose,I would do this,

Code: Select all

class Test {
	FirstFunc(var) {
		MsgBox, This is function 1 called with variable %var%
	}
}
class TestMore extends Test {
	SecondFunc(var) {
		MsgBox, Some other function called with variable %var%
	}
}
ntm := new TestMore
ntm.FirstFunc("first function call")
ntm.SecondFunc("second function call")
If you really do not want the second class, you could also do,

Code: Select all

class Test {
	FirstFunc(var) {
		MsgBox, This is function 1 called with variable %var%
	}
	#include *i <Testlibrary_extended>
}
where, Testlibrary_extended contains,

Code: Select all

SecondFunc(var) {
	MsgBox, Some other function called with variable %var%
}

I do not know exactly why this works
You might be interested in :arrow: Custom objects.

Cheers.

Descolada
Posts: 1098
Joined: 23 Dec 2021, 02:30

Re: Extending pre-existing classes

Post by Descolada » 16 May 2022, 10:05

@Chunjee, unfortunately in my situation it would require reassigning every extended object one by one (this would be quite cumbersome and might lead to mistakes of carelessness):

Code: Select all

class GeneralTest {
	FirstFunc(var) {
		MsgBox, First function called with variable %var%
	}
}

class Test extends GeneralTest {
	SecondFunc(var) {
		MsgBox, Second function called with variable %var%
	}
}

class addonFunctions {
	ThirdFunc(var) {
		MsgBox, Third function called with variable %var%
	}
}

Test.base := addonFunctions
Test.FirstFunc("hello") ; this one fails
Test.SecondFunc("hello")
Test.ThirdFunc("hello")

Test.base := addonFunctions
Test.base.base := GeneralTest
Test.FirstFunc("hello") ; now works
Test.SecondFunc("hello")
Test.ThirdFunc("hello")
Though it does work better than my for-loop idea, so thank you, and I think if nothing better exists then I will use it :)

Btw... It doesn't work if the base class has forbidden assigning values:

Code: Select all

class GeneralTest {
	FirstFunc(var) {
		MsgBox, First function called with variable %var%
	}
	__Set() {
		throw Forbidden!
	}
}

class Test extends GeneralTest {
	SecondFunc(var) {
		MsgBox, Second function called with variable %var%
	}
}

class addonFunctions {
	ThirdFunc(var) {
		MsgBox, Third function called with variable %var%
	}
}

Test.base := addonFunctions ; throws error

@Helgef, your first idea I also already tried, but the library I am extending has methods that return objects of other classes, which I can't extend with your example:

Code: Select all

class SubTest {
	SecondFunc(var) {
		MsgBox, This is function 2 called with variable %var%
	}
}

class Test {
	FirstFunc() {
		return new SubTest
	}
}

class TestMore extends SubTest {
	ThirdFunc(var) {
		MsgBox, Some other function called with variable %var%
	}
}
ntm := new Test
nt := ntm.FirstFunc()
nt.SecondFunc("first function call")
nt.ThirdFunc("hello?") ; ...
The #include way I was hoping to avoid, since it requires modifying the original library, plus if I am extending multiple classes then it would require many files...

Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: Extending pre-existing classes

Post by Helgef » 16 May 2022, 12:08

I do not understand you examlpe. But methods that return objects of other classes has nothing to do with extending.

Cheers.

Descolada
Posts: 1098
Joined: 23 Dec 2021, 02:30

Re: Extending pre-existing classes

Post by Descolada » 16 May 2022, 13:39

Helgef wrote:
16 May 2022, 12:08
I do not understand you examlpe. But methods that return objects of other classes has nothing to do with extending.

Cheers.
My example was supposed to show that your method of creating a new class by extending would provide a way to add functions to the Test class, but I also want to add functions to Subtest and have it work after calling the FirstFunc method. In this case your way wouldn't work.

User avatar
Chunjee
Posts: 1400
Joined: 18 Apr 2014, 19:05
Contact:

Re: Extending pre-existing classes

Post by Chunjee » 17 May 2022, 00:20

Descolada wrote:
16 May 2022, 10:05
@Chunjee, unfortunately in my situation it would require reassigning every extended object one by one (this would be quite cumbersome and might lead to mistakes of carelessness):

I don't know what this means. In your examples you now have three classes? GeneralTest, Test, addonFunctions. Perhaps you should link the library you are working on and the desired added methods. Your examples aren't painting the complete picture.


Descolada wrote:
16 May 2022, 10:05
Btw... It doesn't work if the base class has forbidden assigning values:
I was not able to decipher why class2 extends class1 then class3 follows the base modification.
Recommend you put all the desired methods in one temp class then add to the base. Or follow normal extends inheritance

Code: Select all

GeneralTest.base := addonFunctions ; works fine
GeneralTest.SecondFunc("hello")
GeneralTest.ThirdFunc("world")

class GeneralTest {
	FirstFunc(var) {
		MsgBox, First function called with variable %var%
	}
	__Set() {
		throw Forbidden!
	}
}
class addonFunctions {
	SecondFunc(var) {
		MsgBox, Second function called with variable %var%
	}
	ThirdFunc(var) {
		MsgBox, Third function called with variable %var%
	}
}

Post Reply

Return to “Ask for Help (v1)”