commands as functions (AHK v2 functions for AHK v1)

Discuss the future of the AutoHotkey language
User avatar
jeeswg
Posts: 6472
Joined: 19 Dec 2016, 01:58
Location: UK

Re: commands as functions (AHK v2 functions for AHK v1)

01 Aug 2018, 14:28

- @Helgef: else if !Value.HasKey("ToString") was supposed to be else for Float and Integer. (Error from copying and pasting resulting from trying to match Coco's indentation style, instead of using my auto-indent script.)
- Thanks for the interesting attempt at handling ToString.

- Will Integer become Int, or is there a reason for the long name? Same goes for Str/String. [EDIT:] One reason might be because Float/Integer/String are what Type returns.

- [EDIT:] For the next update perhaps, this, or a version of it.
[v1] v2's CallbackCreate function for AHK v1. - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=53457
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jeeswg
Posts: 6472
Joined: 19 Dec 2016, 01:58
Location: UK

Re: commands as functions (AHK v2 functions for AHK v1)

09 Oct 2018, 00:34

Here is what I'm planning to use for Float/Integer/String. On balance it seemed wisest to keep String simple as this gave predictable deviations from AHK v2, whereas the alternatives were giving unpredictable deviations from AHK v2.

Code: Select all

Float(Value)
{
	if Value is number
		return Value + 0.0
	throw Exception("Type mismatch.", -1)
}
Integer(Value)
{
	if Value is number
		return Value < 0 ? Ceil(Value) : Floor(Value)
	throw Exception("Type mismatch.", -1)
}
String(Value)
{
	if !IsObject(Value)
		return "" Value
	return Value.ToString()
}
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jeeswg
Posts: 6472
Joined: 19 Dec 2016, 01:58
Location: UK

Re: commands as functions (AHK v2 functions for AHK v1)

24 Apr 2019, 23:52

- For an as of yet unreleased Sort function, there's this:

Code: Select all

Sort(String, Options:="", Func:="")
{
	global zAHKFC_SortFunc
	if IsObject(Func)
	{
		zAHKFC_SortFunc := Func
		Options .= " F AHKFC_SortAux"
	}
	else if !(Func = "")
		Options .= " F " Func
	Sort, String, % Options
	return String
}
AHKFC_SortAux(Arg1, Arg2, Offset)
{
	global zAHKFC_SortFunc
	return %zAHKFC_SortFunc%(Arg1, Arg2, Offset)
}
- [EDIT:] And here's a StrCompare function:

Code: Select all

StrCompare(String1, String2, CaseSensitive:=0)
{
	local Output, SCS
	SCS := A_StringCaseSense
	if (CaseSensitive = 1)
		StringCaseSense, On
	else if (SCS = "On")
		StringCaseSense, Locale
	Output := ("" String1 > "" String2) ? 1 : ("" String1 < "" String2) ? -1 : 0
	StringCaseSense, % SCS
	return Output
}
- I'm thinking that I'll release 2 versions of the script, one with the ControlXXX/WinXXX functions unchanged, one with the attempted updates. (The updated ControlXXX/WinXXX backports are bad for quick copying and pasting to a script, as they have dependencies.)

- (I'd already advocated for the following AHK v1/v2 functionality before the ControlXXX/WinXXX changes:)
- Realistically, to fully recreate ControlXXX/WinXXX, I need a way to check if the nth parameter was passed. I.e. a direct approach, instead of using a variadic function as a workaround.
- To fully recreate WinActive/WinExist and other functions, I need a way for a custom function with the same name as a built-in function to call the built-in function e.g. A_BIF.SubStr(...).
- Testing across AHK v1/v2 would be aided if: (a) all ControlXXX functions allowed you to omit the Control parameter, (b) a two-way compatible Loop/LoopXXX were available (I have proposed a solution below).
why was LoopParse (no space) removed? - Page 4 - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=37&t=41821&p=235007#p235007
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jeeswg
Posts: 6472
Joined: 19 Dec 2016, 01:58
Location: UK

Re: commands as functions (AHK v2 functions for AHK v1)

30 May 2019, 17:17

Here's a BufferAlloc function:

BufferAlloc - Syntax & Usage | AutoHotkey v2
https://lexikos.github.io/v2/docs/commands/BufferAlloc.htm
Buffer Object - Definition & Usage | AutoHotkey v2
https://lexikos.github.io/v2/docs/objects/Buffer.htm

Code: Select all

BufferAlloc(Size)
{
	return new Buffer(Size)
}
class Buffer
{
	;note: Buffer.Data does not handle nulls as AHK v2 does
	__New(Size)
	{
		this.SetCapacity("_buf", Size)
		this._size := size
		DllCall("ntdll\RtlFillMemory", "Ptr",this.GetAddress("_buf"), "UPtr",Size, "UChar",0)
	}
	Size
	{
		get
		{
			return this._size
		}
		set
		{
			if !(value = this._size)
				this.SetCapacity("_buf", value)
			if (value > this._size)
				DllCall("ntdll\RtlFillMemory", "Ptr",this.GetAddress("_buf")+this._size, "UPtr",value-this._size, "UChar",0)
			return this._size := value
		}
	}
	Ptr
	{
		get
		{
			return this.GetAddress("_buf")
		}
		set
		{
			throw Exception("Invalid usage.", -1)
		}
	}
	Data
	{
		get
		{
			return StrGet(this.GetAddress("_buf"), this._size/2, "UTF-16")
		}
		set
		{
			throw Exception("Invalid usage.", -1)
		}
	}
	__Get(k, Params*)
	{
		if !(k = "Ptr")
		&& !(k = "Size")
			throw Exception("Unknown property.", -1)
	}
	__Set(k, Params*)
	{
		if !(k = "_size")
		&& !(k = "Data")
		&& !(k = "Ptr")
		&& !(k = "Size")
			throw Exception("Unknown property.", -1)
	}
	__Call(m, Params*)
	{
		if !(m = "GetAddress")
		&& !(m = "SetCapacity")
			throw Exception("Unknown method.", -1)
	}
}
old versions
Last edited by jeeswg on 31 May 2019, 14:32, edited 12 times in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
guest3456
Posts: 2541
Joined: 09 Oct 2013, 10:31

Re: commands as functions (AHK v2 functions for AHK v1)

30 May 2019, 21:11

jeeswg wrote:
30 May 2019, 17:17
Here's a BufferAlloc function:

Code: Select all

BufferAlloc(Size)
{
	return new Buffer(Size)
}
class Buffer
{
	static __id := 0
	__New(Size)
	{
		global
		Buffer.__id++
		zAHKFC_BufferTemp := Buffer.__id
		VarSetCapacity(zAHKFC_Buffer%zAHKFC_BufferTemp%, Size)
		this.__id := Buffer.__id
		this.Ptr := &zAHKFC_Buffer%zAHKFC_BufferTemp%
		this.Size := Size
	}
	__Delete()
	{
		global
		zAHKFC_BufferTemp := this.__id
		zAHKFC_Buffer%zAHKFC_BufferTemp% := ""
	}
	Data
	{
		get
		{
			global
			zAHKFC_BufferTemp := this.__id
			return StrGet(this.Ptr, this.Size/2, "UTF-16")
		}
	}
}
do you really need to populate global scope?

swagfag
Posts: 2611
Joined: 11 Jan 2017, 17:59

Re: commands as functions (AHK v2 functions for AHK v1)

31 May 2019, 05:54

please, replace this with a proper GlobalAlloc raii class lol
Helgef
Posts: 3783
Joined: 17 Jul 2016, 01:02
Contact:

Re: commands as functions (AHK v2 functions for AHK v1)

31 May 2019, 07:09

You should also read the docs on Buffer.data. Although I don't think this property is generally useful. I don't think you can implement .data without relying on undocumented behaviour in v1. Disregarding the pollution of the global variable namespace, interruptions may cause very undesirable behaviour.

Cheers-
User avatar
jeeswg
Posts: 6472
Joined: 19 Dec 2016, 01:58
Location: UK

Re: commands as functions (AHK v2 functions for AHK v1)

31 May 2019, 07:46

@guest3456: do you really need to quote the whole post? Hehe.
Perhaps I can pipe everything through a general '_Main' method in the class, hmm. And store the data as static variables inside it.

@Helgef: Doesn't AHK v1 always truncate returned values, and so there isn't really a solution. Yes, I had thought that .Data wasn't generally too useful.
I've improved the code, and added a comment re. .Data.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 3783
Joined: 17 Jul 2016, 01:02
Contact:

Re: commands as functions (AHK v2 functions for AHK v1)

31 May 2019, 08:06

Code: Select all

static ID := 0
ID++
VarSetCapacity(zAHKFC_Buffer%ID%, Size, 0)
this.__id := ID
This is still not safe with interruptions.
User avatar
jeeswg
Posts: 6472
Joined: 19 Dec 2016, 01:58
Location: UK

Re: commands as functions (AHK v2 functions for AHK v1)

31 May 2019, 08:20

OK, I've fixed the class. Please state if any problems remain with the old/new versions. Cheers.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 3783
Joined: 17 Jul 2016, 01:02
Contact:

Re: commands as functions (AHK v2 functions for AHK v1)

31 May 2019, 08:31

Code: Select all

static Count := 0
Count++
this.__id := Count
still not safe with interruptions.
User avatar
jeeswg
Posts: 6472
Joined: 19 Dec 2016, 01:58
Location: UK

Re: commands as functions (AHK v2 functions for AHK v1)

31 May 2019, 08:41

- I've changed it to this:
this.__id := Count++
- Would anything else remain after that?

- So in short, the problems you mention are because static variables in functions can be changed by multiple (i.e. simultaneous/overlapping) function calls.
- One thing that has come up re. that, is it possible to specify a *non-static* variable, in a function where all the variables are static. A non-static variable is safe because it is unique to the function call.
- These problems are fundamental, but I'd never really had to deal with them before.
- Another issue is that using this.key would be safe, but you can't do var%this.key% in AHK v1 (at present).
- As a workaround, when I use a static variable that I'd rather have as non-static, I bunch it up with other statements into multi-statement. I.e. you can safely use the static variable, within the context of a multi-statement, because the multi-statement can't be interrupted.
- Another workaround could be to add a parameter variable, to the list of the function's/method's parameters, and use that.

- [EDIT:] It turns out that you *can* use 'local' to make a variable, in an assume-static function, non-static. This is stated in the documentation, and demonstrated here:

Code: Select all

q:: ;test non-static variable in an assume-static function
oFunc := Func("MyStaticNonStaticFunc").Bind(6)
SetTimer, % oFunc, -500
MyStaticNonStaticFunc(3)
return

MyStaticNonStaticFunc(vNum)
{
	static
	local vNonStat
	vStat := vNum
	vNonStat := vNum
	MsgBox, % vStat " " vNonStat
	MsgBox, % vStat " " vNonStat
}
- One reason for uncertainty, is that 'local' plus 'static', as mentioned in the quote below, results in static variables. This sounds like a contradiction, local (non-static) variables that are static, but, 'local', in this context, is used to avoid situations where dynamic variable names, e.g. %myvar%, refer to global variables.
Functions - Definition & Usage | AutoHotkey
https://autohotkey.com/docs/Functions.htm#static
In assume-static mode, any variable that should not be static must be declared as local or global (with the same exceptions as for assume-local mode, unless force-local mode is also in effect).

[v1.1.27+]: Force-local mode can be combined with assume-static mode by specifying local and then static, as shown below. This allows the function to use force-local rules but create variables as static by default.
Last edited by jeeswg on 31 May 2019, 09:18, edited 3 times in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 3783
Joined: 17 Jul 2016, 01:02
Contact:

Re: commands as functions (AHK v2 functions for AHK v1)

31 May 2019, 08:54

So in short
yes
is it possible to specify a *non-static* variable, in a function where all the variables are static
assume-static mode wrote:In assume-static mode, any variable that should not be static must be declared as local or global
Helgef
Posts: 3783
Joined: 17 Jul 2016, 01:02
Contact:

Re: commands as functions (AHK v2 functions for AHK v1)

31 May 2019, 09:00

creating one variable per call is still a pretty poor approach. You can use another allocation method than varsetcapacity, either via dllcall or setCapacity.
User avatar
jeeswg
Posts: 6472
Joined: 19 Dec 2016, 01:58
Location: UK

Re: commands as functions (AHK v2 functions for AHK v1)

31 May 2019, 09:37

Can you explain further what you mean? Thanks.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 3783
Joined: 17 Jul 2016, 01:02
Contact:

Re: commands as functions (AHK v2 functions for AHK v1)

31 May 2019, 09:45

Example

Code: Select all

class Buffer
{
	;note: Buffer.Data does not handle nulls as AHK v2 does
	__New(Size)
	{
		this.setcapacity("buf", size) ; doesn't zero init.
		this._size := size
	}
	Ptr
	{
		get
		{
			return this.getAddress("buf")
		}
		; set should throw
	}
	Size
	{
		get
		{
			return this._size
		}
		; set should realloc
	}
	Data
	{
		get
		{
			return StrGet(this.Ptr, this.Size/2, "UTF-16")
		}
		; set should throw.
	}
	; you can use __set or __get to throw for other invalid use.
}
User avatar
jeeswg
Posts: 6472
Joined: 19 Dec 2016, 01:58
Location: UK

Re: commands as functions (AHK v2 functions for AHK v1)

31 May 2019, 09:47

ObjSetCapacity to create the key, ObjGetAddress to get the address.
But wasn't there some problem where object keys are automatically updated, and so can't store binary data?
And DllCall, which Winapi function?
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 3783
Joined: 17 Jul 2016, 01:02
Contact:

Re: commands as functions (AHK v2 functions for AHK v1)

31 May 2019, 09:57

But wasn't there some problem where object keys are automatically updated, and so can't store binary data?
No.

You can call malloc, swagfag mentioned GlobalAlloc.
User avatar
jeeswg
Posts: 6472
Joined: 19 Dec 2016, 01:58
Location: UK

Re: commands as functions (AHK v2 functions for AHK v1)

31 May 2019, 10:13

- Thanks for the Winapi mentions. Although, I might have thought that AHK variables were better optimised versus using DllCall.

- RtlFillMemory can be used to fill a buffer with zeros, after ObjSetCapacity.

- Here's a link, where StrLen works differently on string variables versus strings stored in object keys.
Allow AutoHotkey to Handle Binary Data - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=13&t=61502&p=265002#p265002
- Since storing binary data in an object key is undocumented, how am I to know that the class will work reliably? You appear to be promoting the use of undocumented functionality, this is surprising!
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA

Return to “AutoHotkey v2 Development”

Who is online

Users browsing this forum: No registered users and 6 guests