Page 1 of 2

[Request] Module Export

Posted: 17 Oct 2018, 08:29
by Chunjee
Hello,

I am officially requesting Moduled Exports in the likeness of Node.js: https://nodejs.org/api/modules.html
It would be nice to be able to use external functions without following the naming convention the function creator chose.

Psuedocode:

Code: Select all

Class exampleClass{
	
	__New() {
	}
	

	exampleMethod(parameter) {
		;do something
	}
	
Export(exampleClass)

Code: Select all

exampleFunction(parameter1, parameter2) {
	;do something
}

Export(exampleFunction)

Code: Select all

Import(module.ahk)
myclassinstance := new exampleClass()

mynamedfunction := Import(function.ahk)
mynamedfunction("foo","bar")
#import %filename% as %varname% also a good suggestion.



As a note, its easy in javascript as everything including functions can be saved as objects and transported elsewhere:

Code: Select all

function myCoolFunction() {
// do something
}
module.exports = {
	myCoolFunction: myCoolFunction
};

Code: Select all

var myCoolFunctionInstance = require('myCoolFunction');
// searches recursively in parent directory for myCoolFunction library and imports as user specified object.
myCoolFunctionInstance.doSomething()

In addition: I have been working around the outdated way AHK sources code from other files, but increasingly I am coming up against an issue where the same function cannot be defined twice:
Known limitation: Currently, the name of each subroutine (label) must be unique among those of the entire script. The program will notify you upon launch if there are duplicate labels.
This turns into an issue when for example two libraries share a dependency on a third library. In the theoretic circumstance where all libraries are updated and not conflicting, you still have not solved for situations where a library requires an older version of a library (difference in argument order, accepted types, etc)


Notes and links:
https://autohotkey.com/docs/Functions.htm#lib

Re: Module Export

Posted: 17 Oct 2018, 08:37
by nnnik
#import %filename% as %varname% would be my prefered syntax for this.
All files loaded like this receive their own scope and settings.
They also receive their own A_Variables and functions.
In this syntax the person creating the library does not need to care about the way it is imported and we can keep the current libraries unchanged.

Re: [Request] Module Export

Posted: 18 Oct 2018, 18:38
by kczx3

Re: [Request] Module Export

Posted: 18 Dec 2018, 15:23
by Chunjee
https://autohotkey.com/docs/commands/_Include.htm
#IncludeAgain allows multiple inclusions of the same file, while being the same as #Include in all other respects.
I'll see if this can be leveraged in any way.

Re: [Request] Module Export

Posted: 18 Dec 2018, 16:48
by kczx3
Can you explain how that may be helpful?

Re: [Request] Module Export

Posted: 19 Dec 2018, 15:25
by Chunjee
For some reason, I thought it would allow multiple a the same function to be defined more than once but I was wrong.

Re: [Request] Module Export

Posted: 15 Feb 2019, 03:01
by coffee
This *may* be emulated using AutoHotkey_H (latest version, v2) if you want to experiment. You can try asking HotkeyIt for some help with this. He can probably iron out any quirks to make it work 'neatly', if you propose something.

Raw proof of concept:
For a file called "namedModule.ahk"

Code: Select all

exports.world := func("world")
exports.xvar := "holy canoli"
world()
{
	msgbox("inside")
}
It could be "required" as

Code: Select all

mymod := require("namedModule")

mymod.world()
msgbox(mymod.xvar)


;/////////////////// REQUIRE
require(mod)
{
	static CRLF := "`r`n"
	local obj := CriticalObject()
	local script := FileRead(mod . ".ahk")
	
	script := (
		"#persistent" CRLF
		"exports := CriticalObject(" (&obj) ")" CRLF
		script
	)
	ThreadObj(script).ExitApp()
	return obj
}
That example is working in my setup, albeit finicky.
I'm unaware of memory leaks, or performance ramifications, since I literally just sprung this up and I don't really use the multithreading features of autohotkey_h that much.

Re: [Request] Module Export

Posted: 15 Feb 2019, 10:56
by kczx3
What do you mean by finicky?

Re: [Request] Module Export

Posted: 16 Feb 2019, 00:29
by coffee
kczx3 wrote:
15 Feb 2019, 10:56
What do you mean by finicky?
If you look at it wrong it throws an access violation.
Doing msgbox(type(mymod.world)) above the mymod.world() call in previous post either hangs, throws access violation or works, or all three at the same time ¯\_(ツ)_/¯

Using ahkthread seems more consistent, though I don't know if resources are released automatically. Doing .ahkterminate() throws access violation. Maybe someone who uses autohotkey_h a lot and its variety of ways of creating threads can get it to work for their use.

Code: Select all

world()
{
	global glob
	msgbox(glob " | " superglob)
}

glob := "global"
global superglob := "superglobal"

class test {
	method1()
	{
		msgbox("method1")
	}
	
}

exports.world := func("world")
exports.xvar := "holy canoli"
exports.classify := test

Code: Select all

mymod := require("namedmodule")

; msgbox(type(mymod.world))
mymod.world()
mymod.classify.method1()
msgbox(mymod.xvar)


;/////////////////// REQUIRE
require(mod)
{
	static CRLF := "`r`n"
	local obj := CriticalObject()
	
	script := (
		"#persistent" CRLF
		"exports := CriticalObject(" (&obj) ")" CRLF
		"#include " mod ".ahk"
	)
	; ThreadObj(script).ExitApp()
	AhkThread(script)
	return obj
}


Re: [Request] Module Export

Posted: 17 Feb 2019, 10:59
by Chunjee
Thanks I'll take a look at that.

Re: [Request] Module Export

Posted: 20 Jan 2020, 10:25
by Chunjee
This request is still open. I guess #Include just works on the global namespace so there's really no clean way to build classes that depend on classes or functions because any change at the global namespace will screw them up.

Re: [Request] Module Export

Posted: 20 Jan 2020, 11:43
by swagfag
i dont think this is gonna be needed if namespaces were to be introduced
there was a fully working PR by @Helgef that just festers nowadays..

Re: [Request] Module Export

Posted: 21 Jan 2020, 08:01
by nnnik
I think Helgefs concept of namespaces was overly bloated and complex.
Though it definitively would work.

Re: [Request] Module Export

Posted: 21 Jan 2020, 08:31
by kczx3
nnnik wrote:
21 Jan 2020, 08:01
I think Helgefs concept of namespaces was overly bloated and complex.
Though it definitively would work.
It is certainly a complicated issue to solve due to the very global nature of many of AHKs settings

Re: [Request] Module Export

Posted: 21 Jan 2020, 10:49
by Helgef
Bloated and complex, perhaps in regards to the implementation, but usage is very simple and offers powerful possibilities, imo. However, I did start to rewrite it just a few days ago, I will make the implementation simpler (I hope), but usage will be much more limited. Whether I endure the project or not remains to be seen though ;) .

Cheers.

Re: [Request] Module Export

Posted: 21 Jan 2020, 11:33
by Chunjee
Helgef wrote:
21 Jan 2020, 10:49
Bloated and complex, perhaps in regards to the implementation, but usage is very simple and offers powerful possibilities, imo. However, I did start to rewrite it just a few days ago, I will make the implementation simpler (I hope), but usage will be much more limited.
Where do I find this?

Re: [Request] Module Export

Posted: 21 Jan 2020, 12:21
by Helgef
It is for v2, iirc a103. See :arrow: #142, :arrow: documentation and executables.
Cheers.

Re: [Request] Module Export

Posted: 21 Jan 2020, 16:42
by HotKeyIt
Here is an example for AHK_H v2, CriticalObject is only required if you want to use it in multi-threading environment:

Code: Select all

module:="
(
world(this){
	global glob
	msgbox(glob " | " superglob)
}
glob := "global"
global superglob := "superglobal"
class test {
	method1(){
		msgbox("method1")
	}	
}
exports.DefineMethod("world",func("world"))
exports.xvar := "holy canoli"
exports.classify := test.new()
)"

mymod := require(module)

mymod.world()
mymod.classify.method1()
msgbox(mymod.xvar)

require(module){
	thread:=ExeThread("#persistent`nexports := CriticalObject(" (&obj := CriticalObject()) ")`n" module "`nA_IMPORT_FINALIZED:=1") ; to import from string
	; thread:=ExeThread("#persistent`nexports := CriticalObject(" (&obj := {}) ")`n#import " module ".ahk`nA_IMPORT_FINALIZED:=1") ; to import a file
    While !thread.ahkgetvar("A_IMPORT_FINALIZED")
      Sleep 10
	return obj
}

Re: [Request] Module Export

Posted: 26 Jun 2020, 12:44
by Chunjee
In case the OP was not clear. This is needed because if you want to make a library that makes use of another library you are likely screwed because ahk doesn't let you #include in a scoped manner and you can't define functions at anything but the global scope.

You also can't define functions with the same name more than once. So if Library A and library B both want to include a CPU() function, there will be an error because it can't be defined twice.


This isn't a big deal for 90% of ahk users who just want some simple scripts but it makes building long term progress a fucking nightmare because you cannot build on the effort of other libraries and tools without re-writing each library not to conflict or worse, writing everything your library needs to do on it's own. We are familiar with the meaning of "standing on the shoulders of giants" but it is difficult to make use of giant's shoulders when ahk doesn't make it easy to for giants to congregate. Meaning sure you can #include libraries in your script. But what if that library wants to #inlcude things? It becomes hard to stack libraries because of conflicts and flat scope restrictions, as well as inflexible naming of included libraries, etc.
GeekDude wrote:I like AHK because I have to build everything from scratch every time

Re: [Request] Module Export

Posted: 26 Jun 2020, 12:55
by Helgef
This isn't a big deal for 90% of ahk users who just want some simple scripts

Many more scripts could be simple if there were many good, non-conflicting libraries available :thumbup:.

But helgef, there are many good non-conflicting libraries! Sure, but maybe there would be more if some developers didn't feel that writing such libraries was a
nightmare because you cannot build on the effort of other libraries and tools without re-writing each library not to conflict and bring everything it needs to the table on it's own.
Anyways, I made another attempt at this :arrow: #162.

Cheers.