conversion logic, v1 = -> v1 := -> v2, two-way compatibility

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

Re: conversion logic, v1 = -> v1 := -> v2, two-way compatibility

28 Jan 2017, 07:25

First attempts at key functions that allow two-way compatibility:

Note: I am working on amendments to Commands As Functions,
so that the functions would be identical to the standard functions in AHK v2,
with any additional non-AHK v2 functions at the bottom.

I have now fully converted an example 4200-line script, to make it AHK v1/v2 two-way compatible,
the only pressing issue is double quotes, "" in AHK v1, `" in AHK v2,
a consistent method perhaps `" for both if doable, would be immensely helpful
with conversion. Apart from that it seems that AHK v1 has everything it needs
in order to make two-way compatibility quite feasible.

For example, fortunately this change was made recently:
Loop (parse a string)
https://autohotkey.com/docs/commands/LoopParse.htm
[v1.1.21+]: This parameter can be an % expression, but the percent-space prefix must be used.

Code: Select all

;==================================================

;note: this is intended to appear in the new Commands As Functions library:
;for AHK v1 only (equivalent to AHK v2's Deref function)
Deref(String) {
	Transform, OutputVar, Deref, % String
	Return OutputVar
}

;==================================================

JEE_ParamFirst(oParams*)
{
Return oParams[1]
}

JEE_ParamLast(oParams*)
{
Return oParams[oParams.MaxIndex()]
}

JEE_ParamCount(oParams*)
{
Return oParams.MaxIndex()
}

;==================================================

JEE_InStr1(ByRef Haystack, Needle, CaseSensitive:=false, StartingPos:=1, Occurrence:=1) {
	if (StartingPos <= 0) && !(SubStr(A_AhkVersion, 1, 2) = "1.")
	StartingPos--
	Return InStr(Haystack, Needle, CaseSensitive, StartingPos, Occurrence)
}
JEE_InStr2(ByRef Haystack, Needle, CaseSensitive:=false, StartingPos:=1, Occurrence:=1) {
	if (StartingPos <= -1) && (SubStr(A_AhkVersion, 1, 2) = "1.")
	StartingPos++
	Return InStr(Haystack, Needle, CaseSensitive, StartingPos, Occurrence)
}
JEE_SubStr1(String, StartingPos, Length:="") {
	if (StartingPos <= 0) && !(SubStr(A_AhkVersion, 1, 2) = "1.")
	StartingPos--
	if (vLength = "")
	Return SubStr(String, StartingPos)
	Return SubStr(String, StartingPos, Length)
}
JEE_SubStr2(String, StartingPos, Length:="") {
	if (StartingPos <= -1) && (SubStr(A_AhkVersion, 1, 2) = "1.")
	StartingPos++
	if (StartingPos = 0)
	Return ""
	if (vLength = "")
	Return SubStr(String, StartingPos)
	Return SubStr(String, StartingPos, Length)
}
JEE_RegExMatch1(Haystack, NeedleRegEx, UnquotedOutputVar:="", StartingPos:=1) {
	if (StartingPos <= 0) && !(SubStr(A_AhkVersion, 1, 2) = "1.")
	StartingPos--
	Return RegExMatch(Haystack, NeedleRegEx, UnquotedOutputVar, StartingPos)
}
JEE_RegExMatch2(Haystack, NeedleRegEx, UnquotedOutputVar:="", StartingPos:=1) {
	if (StartingPos <= -1) && (SubStr(A_AhkVersion, 1, 2) = "1.")
	StartingPos++
	Return RegExMatch(Haystack, NeedleRegEx, UnquotedOutputVar, StartingPos)
}
JEE_RegExReplace1(Haystack, NeedleRegEx, Replacement:="", OutputVarCount:="", Limit:=-1, StartingPos:=1) {
	if (StartingPos <= 0) && !(SubStr(A_AhkVersion, 1, 2) = "1.")
	StartingPos--
	Return RegExReplace(Haystack, NeedleRegEx, Replacement, OutputVarCount, Limit, StartingPos)
}
JEE_RegExReplace2(Haystack, NeedleRegEx, Replacement:="", OutputVarCount:="", Limit:=-1, StartingPos:=1) {
	if (StartingPos <= -1) && (SubStr(A_AhkVersion, 1, 2) = "1.")
	StartingPos++
	Return RegExReplace(Haystack, NeedleRegEx, Replacement, OutputVarCount, Limit, StartingPos)
}

;==================================================

;note: no special handling for double comma
JEE_StrContains(ByRef vText, ByRef vNeedles, vDelim:=",", vCaseSen:=0)
{
vDelim := SubStr(vDelim, 1, 1)

Loop, Parse, vNeedles, % vDelim
if InStr(vText, A_LoopField, vCaseSen)
Return 1

Return 0
}

;note: no special handling for double comma
JEE_StrIn(ByRef vText, ByRef vNeedles, vDelim:=",", vCaseSen:=0)
{
vSCS := A_StringCaseSense
StringCaseSense, % vCaseSen ? "On" : "Off"
Loop, Parse, vNeedles, % vDelim
if !("" vText <> "" A_LoopField) ;if not different (i.e. if same)
{
StringCaseSense, % vSCS
Return 1
}

StringCaseSense, % vSCS
Return 0
}

JEE_Between(vNum, vRange1, vRange2)
{
if (vNum >= vRange1) && (vNum <= vRange2)
Return 1
else
Return 0
}

;==================================================
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: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: conversion logic, v1 = -> v1 := -> v2, two-way compatibility

02 Feb 2017, 10:04

I thought I would have a go at converting (in this order):
Acc.ahk
AccViewer Source.ahk
Anchor.ahk
iWB2 Learner UPDATED.ahk
Around 20 miscellaneous functions.
(I.e. to correct everything I use not written by me,
probably only leaving Gdip.ahk and VA.ahk.)

I appear to have Acc.ahk converted, to make it two-way compatible,
however I am not 100% clear on replacing ComObjEnwrap() and ComObj().
What is the replacement for ComObj(), also, I haven't used ObjAddRef before so am not sure of its significance.

Acc.ahk is actually a relatively easy script to convert if someone else
wants to have a go, and then compare attempts.
Basically = to := in function definitions, order of elements after a Return,
and various ternary operator corrections, and also replacing "" with Chr(34) twice.
Oh and some replacing of 'if var in'.
Are there StrIn/StrContains/Between/StrIsType functions or equivalent in AHK v2 yet?
Oh and StringReplace to StrReplace twice.

[EDIT:]
Note: in AHK v1, it appears that any 'function' starting with ComObj even
ComObjDUMMY, returns no errors. I have tried to list every ComObj function here:
list of every command/function/variable from across all versions - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?t=27321
Last edited by jeeswg on 02 Feb 2017, 12:54, edited 2 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: 3454
Joined: 09 Oct 2013, 10:31

Re: conversion logic, v1 = -> v1 := -> v2, two-way compatibility

02 Feb 2017, 10:19

jeeswg wrote: (I.e. to correct everything I use not written by me,
probably only leaving Gdip.ahk and VA.ahk.)
Gdip is already done, if you make improvements please base them off that, and submit them there

User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: conversion logic, v1 = -> v1 := -> v2, two-way compatibility

02 Feb 2017, 14:06

Wow, apparently your updated Gdip script is two-way compatible, so you've been onboard with my two-way compatibility project all along!
Out of interest were there any major problems converting Gdip.
I noticed in the Gdip script I'm currently using there is no use of Return with multiple parameters, which when present is a major conversion headache.

Regarding Acc and ComObj:

v2-changes
https://autohotkey.com/v2/v2-changes.htm
•ComObjMissing() (write two consecutive commas instead)
•ComObjUnwrap() (use ComObjValue() instead, and ObjAddRef() if needed)
•ComObjEnwrap() (use ComObject() instead, and ObjAddRef() if needed)
•ComObjXXX() where XXX is anything other than one of the explicitly defined ComObj functions (use ComObjActive() or ComObject() instead).

ComObjActive()
https://autohotkey.com/docs/commands/ComObjActive.htm
To write more future-proof code, use the following instead:
ComObject := ComObject(9, DispPtr, 1), ObjAddRef(DispPtr)
DispPtr := ComObjValue(ComObject), ObjAddRef(DispPtr)

Although it hasn't affected me yet, the ComObjMissing() change might be a two-way compatibility problem.
There is nothing specific said about ComObj. So I'll do more investigating ...

Regarding an AHK wish list:
I feel pretty certain now it would be good if AHK v2 can allow #NoEnv to remain in a script even if it serves no purpose in AHK v2, for two-way compatibility with AHK v1.
The "" `" double quotes issue is major.
Built-in functions corresponding to ParamFirst/ParamLast, InStr1/InStr2, SubStr1/SubStr2, (and the RegEx ones,)
above, are definitely worth considering for AHK v1 and AHK v2.

[EDIT:]
Acc.ahk actually says at the top:
; Modified ComObjEnwrap params from (9,pacc) --> (9,pacc,1)
; Changed ComObjUnwrap to ComObjValue in order to avoid AddRef (thanks fincs)

I have looked up ObjAddRef() it seems to be about tidying up in order to free memory.
It may be quite fiddly to correct all of this in Acc.ahk, while making minimal edits to the script.
ObjAddRef() / ObjRelease()
https://autohotkey.com/docs/commands/ObjAddRef.htm

For reference, I believe the script should work fine if I miss out ObjAddRef/ObjRelease, although it's bad form.

[EDIT 2:]
In Acc.ahk, it looks like I can replace 'ComObj(' with 'ComObject(', based on:
ComObjActive()
https://autohotkey.com/docs/commands/ComObjActive.htm
vref := ComObject(0x400C, &var)

Note: it was hard to find ComObject in the help, I only found it because I had a txt copy of the help chm, also the first definition for it was:
ComObject := ComObjActive(CLSID)
which did not look promising.
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: 3454
Joined: 09 Oct 2013, 10:31

Re: conversion logic, v1 = -> v1 := -> v2, two-way compatibility

02 Feb 2017, 20:42

jeeswg wrote:Wow, apparently your updated Gdip script is two-way compatible, so you've been onboard with my two-way compatibility project all along!
i had a specific need to use Gdip in a v2 script, so i started the conversion. i think IF libraries like this can allow backwards compatibility, thats great. but there are some things that just cannot convert properly so its pointless to try to make a generic converter for all scripts. i'm of the opinion that v2 needs to get into Beta ASAP and all of the focus should be on pushing users to the new version
jeeswg wrote: Out of interest were there any major problems converting Gdip.
check the commit history to see the changes. i believe RegExMatch had to be changed to always use an object as outputvar

lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

Re: conversion logic, v1 = -> v1 := -> v2, two-way compatibility

03 Feb 2017, 03:38

Although it hasn't affected me yet, the ComObjMissing() change might be a two-way compatibility problem.
ComObjMissing() is obsolete, as it says in the v1 manual.
I feel pretty certain now it would be good if AHK v2 can allow #NoEnv to remain in a script even if it serves no purpose in AHK v2, for two-way compatibility with AHK v1.
I disagree. Anything with no purpose other than backward-compatibility does not belong in v2.

In early versions one could define an empty function #NoEnv() in stdlib, and then #NoEnv would be a call to this function. But I've since reserved the # character for other uses.
The "" `" double quotes issue is major.
I agree that v1 should support `", but the task of implementing it holds no interest for me.
I have looked up ObjAddRef() it seems to be about tidying up in order to free memory.
No, it's the polar opposite...
also the first definition for it was:
ComObject := ComObjActive(CLSID)
which did not look promising.
Don't the big yellow blocks give away the fact that there are multiple functions documented on that page? Actually, there's just one function with multiple names, as it explains on the page.
In current versions, any function-call beginning with "ComObj" that does not match one of the other COM functions actually calls ComObjActive.
Note: it was hard to find ComObject in the help,
It's the first result if you use the offline help search. It's also listed as "ComObj...()" in the help index (offline and online). It's probably easier to see the relevance once you've read the page.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: conversion logic, v1 = -> v1 := -> v2, two-way compatibility

09 Feb 2017, 15:08

In current versions, any function-call beginning with "ComObj" that does not match one of the other COM functions actually calls ComObjActive.
Wow, so all roads lead to Com!
It's the first result if you use the offline help search. It's also listed as "ComObj...()" in the help index (offline and online). It's probably easier to see the relevance once you've read the page.
Apologies, I never use the offline search,
I often program from my TV, but AutoHotkey Help is too small on my TV so I
tend to search in Google, to find things, else the txt.

Regarding ComObjMissing, I searched my scripts, I only use it here:
Can m be defined here, to give the same value, by some other means?

Code: Select all

m := ComObjMissing() ; This will make a field use the default value.
oXl.Workbooks.OpenText("C:\dummyfile.txt", m, m, m, 1, 0, 1, 0, 0, 0, 0, m, m, m, m, m, m, m)
Thank you very much for your comments.

==================================================

One comment I want to make about AHK v1/AHK v2 two-way compatibility,
is taking old code and quickly converting it, or converting someone else's function libraries,
or writing new AHK v1 code so that it is two-way compatible.
In these cases using custom functions will often make it far easier to convert things.
But for example, you do not necessarily want to add ugly compatibility functions,
when you convert libraries such as Acc.ahk, or every time you share some code.
I would strongly advocate for careful consideration, regarding which, often very simple functions,
would be useful as standard AutoHotkey functions in relation to conversion, and hastening the growth of AHK v2.

I've been tempted to add this to Acc.ahk:

Code: Select all

Acc_ParamFirst(oParams*)
{
Return oParams[1]
}
to ease conversion, but when you add functions in this way to libraries it's rather ugly.
(Adding such a function to my own libraries is fine.)
Having this as a default function (the name can be completely different),
will negate a plethora of conversion issues.

Keeping StrRight as a default function for AHK v1 and AHK v2,
would negate issues to do with SubStr and negative values.
In fact I think that StrTrimLeft and StrTrimRight are sufficiently useful
that they should be kept in AHK v2 also.

I would also advocate for the Deref function (already in AHK v2) to be included in AHK v1.

Code: Select all

;version 1
(StrLen(vMonth)=1) ? (vMonth := "0" vMonth) : ""
(StrLen(vDay)=1) ? (vDay := "0" vDay) : ""
vDate := vYear vMonth vDay vTime

;version 2
vIsAhkV1 := (SubStr(A_AhkVersion,1,2) = "1.")
vMonth := SubStr("0" vMonth, vIsAhkV1-2)
vDay := SubStr("0" vDay, vIsAhkV1-2)
vDate := vYear vMonth vDay vTime

;version 3
vDate := vYear . StrRight("0" vMonth, 2) . StrRight("0" vDay, 2) . vTime
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

Re: conversion logic, v1 = -> v1 := -> v2, two-way compatibility

10 Feb 2017, 21:34

Can m be defined here, to give the same value, by some other means?
I guess "as it says in the v1 manual" was too subtle. If you read it, it will tell you what to use instead of ComObjMissing(). Not that you should even need to read that; you can omit parameters the same way as with every other function or method, and the same as in VBScript.

If, for some reason, you need the parameter to vary - i.e. supply a value sometimes and omit it at other times - you can write separate calls with or without the parameter (as numerous other languages would require), or use a variadic call where the parameter array may or may not define a value for the parameter.

Although I wouldn't recommend using it because a more general method will always work, there is a direct equivalent of ComObjMissing(). After all, that function merely produces an object representing a VARIANT with specific values. It's not very well documented, but you can read about it here.

Code: Select all

missing := ComObjMissing()  ; AutoHotkey v1 only

vt := ComObjType(missing)
scode := ComObjValue(missing) & 0xffffffff  ; '&' because the value of VT_ERROR is 32-bit.
MsgBox % format("ComObject({}, 0x{:x})", vt, scode)
I would also advocate for the Deref function (already in AHK v2) to be included in AHK v1.
I, on the hand, think that perhaps Deref should be removed and script authors should be encouraged to use alternative techniques. Its function is very similar to Format_v (a currently-user-defined version of Format which accepts an associative array instead of a parameter list), but Format_v gives more control over formatting and is sometimes more convenient ({xxx} vs `%xxx`%).
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: conversion logic, v1 = -> v1 := -> v2, two-way compatibility

23 Feb 2017, 15:46

@lexikos
Thanks very much re. ComObjMissing(), I now have:

Code: Select all

;VT_ERROR     =    0xA  ; Error code (32-bit integer)
;m := ComObjMissing() ;AHK v1
;m := ComObject(10, 0x80020004) ;AHK v1/v2
;m := ComObject(0xA, 0x80020004) ;AHK v1/v2
I'm trying to learn all the key things about objects, for conversions, and a possible tutorial, and this is just the sort of classic thing that should be in it.

==================================================

To anyone interested.
guest3456's conversion of Gdip_All.ahk is an interesting example of what's involved in converting between AHK v1/v2.

Download links (before/after):
Gdip_All.ahk
https://www.dropbox.com/s/0e9gdfetbfa8v0o/Gdip_All.ahk
[mentioned on]
GDI+ standard library 1.45 by tic - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?t=6517

GitHub - mmikeww/AHKv2-Gdip: Gdip_All library compatiable with AHK v1.1 and AHK v2.
https://github.com/mmikeww/AHKv2-Gdip
[mentioned on]
Gdip - v2 ready - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?t=13738

I copied the files and compared them with WinMerge, doing the following to isolate the main changes (77 of them):
- Convert LFs to CRLFs if required.
- Remove lines that begin with ';'.
- Replace '`r`n%A_Space%%A_Space%%A_Space%' with '`r`n`t' (one of those times I wish I had `s).
- Replace ':=' with '=' (many code lines if you copied them from the script would now not work btw).
- Remove trailing whitespace.

==================================================

Some comments on the conversion, apart from well done, good job:

- There was a fair bit of changing StringSplit to StrSplit required.
- There was some renaming variables from G to _G, E to _E, I'm not sure exactly why, although it is good for clarity.
- Since if var in/contains is not currently available, changes like the following were made:

Code: Select all

if Extension not in BMP,DIB,RLE,JPG,JPEG,JPE,JFIF,GIF,TIF,TIFF,PNG
;to
if !RegExMatch(Extension, "^(?i:BMP|DIB|RLE|JPG|JPEG|JPE|JFIF|GIF|TIF|TIFF|PNG)$")

if ext in exe,dll
;to
if RegExMatch(Extension, "^(?i:exe|dll)$")
- I didn't know this regarding 'if var is type', this currently works on AHK v2:

Code: Select all

Integer := "Integer"
If Var Is Integer
- Is it necessary to compare as a string? I.e. 2 v. "2".

Code: Select all

pattern_opts := (A_AhkVersion < "2") ? "iO)" : "i)"
(pattern_opts := (A_AhkVersion < "2")) ? "iO)" : "i)" ;does the same as the line above
==================================================

I did some tests regarding functions and script inclusion (yes they are fairly basic tests):

If I refer to MyLib_Func1 in a script, without including the MyLib script as a whole, and MyLib_Func1 refers to Func2 (where Func2 is in MyLib, but doesn't start with 'MyLib_'), that function will be able to run, despite not starting with 'MyLib'.

But if there is a Func2 in MyLib and in another script included by the script, the script does not load and shows the 'Duplicate function definition.' error.

Thus if I add in extra functions, that I'd rather not have to add to a library, my choice will be to call them something like MyLibX_Func2() for a library called MyLib, to avoid any clashes with a Func2 in another script.

One key thing this allows you do to is this:

Code: Select all

MyLib_DoesNothingFunction() ;I would call this: MyLib_Load()
FuncInMyLibWithoutTheMyLibPrefix()
By running a dummy function, it gives you access to all the other functions, that don't have a prefix. Very nice. I'm glad to now know this.
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: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: conversion logic, v1 = -> v1 := -> v2, two-way compatibility

24 Feb 2017, 19:30

I suddenly realised, wait, is there a two-way compatible way to get the command line parameters?

Well SKAN to the rescue it would appear, with one of his classic functions.
Args() - Returns command line parameters as array - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?t=4357

But I'd already had a go first at parsing them. It appears to work well, no guarantees.

I couldn't find any other AutoHotkey command line parsers, although if there are any I'd like to compare approaches.

Code: Select all

;a two-way compatible AHK v1/v2 script
;a guide to parsing the AutoHotkey command line:
;e.g.
;BLANK "PATH" SWITCH SWITCH "PATH" "PARAM" "PARAM" "PARAM"
;1      2     3              4    5 6     7 8     9 10    11
;BLANK  PATH  SWITCH SWITCH "PATH" "PARAM" "PARAM" "PARAM"
;1                           2    3 4     5 6     7 8     9
;BLANK "PATH"               "PATH" "PARAM"  PARAM  "PARAM"
;1      2     3              4    5 6     7         8     9
;BLANK "PATH"                PATH  "PARAM"  PARAM  "PARAM"
;1      2     3                     6     7         8     9

;if parse by double quotes:
;- imagine a blank/non-blank first item before the first double quote
;- even items are complete items
;- odd items need to be parsed by spaces
;- ignore blank items when counting items
;start with a count of -2
;- if an item does not start with '\', increment count
;- if an item does start with '\', ignore it
;once the count has reached 0:
;- we have passed the exe path/switches/script path and are now parsing parameters
;- items that start with '\' are now *not* ignored

;==================================================

;parsing the AutoHotkey command line:
vCmdLn := DllCall("kernel32\GetCommandLineW", Str)
;vCmdLn := Clipboard

vCount := -2
Loop, Parse, % vCmdLn, % Chr(34)
{
	vTemp := A_LoopField
	if (A_Index & 1)
		Loop, Parse, % vTemp, % " "
		{
			vTemp2 := A_LoopField
			if (vTemp2 = "")
			|| ((vCount < 0) && (SubStr(vTemp2, 1, 1) = "/"))
				continue
			vCount++
			if (vCount > 0)
				vArg%vCount% := vTemp2
		}
	else
	{
		if (vTemp = "")
		|| ((vCount < 0) && (SubStr(vTemp, 1, 1) = "/"))
			continue
		vCount++
		if (vCount > 0)
			vArg%vCount% := vTemp
	}
}

vArg0 := vCount
vOutput := vArg0 "`r`n"
Loop, % vArg0
	vOutput .= vArg%A_Index% "`r`n"

MsgBox % vOutput
Return
It's easier than it seems to select and run a bit of code, see code below. When you select and run some code, it often helps to get the text from a variable or the clipboard, and to end with a MsgBox.

Btw it's currently very fiddly to define a string that contains double quotes in a two-way compatible manner, you'll probably need to use Chr(34), better to use the clipboard.

Code: Select all

;an AHK v1 script
^1::
^2::
vPathAhk1U64 = ;define here
vPathAhk2U64 = ;define here

;vText := JEE_GetSelectedText()
Clipboard := ""
SendInput ^c
ClipWait, 3
vText := Clipboard

if !(SubStr(vText, 1-2) = "`r`n")
	vText .= "`r`n"
vPath = %A_Desktop%\z test %A_Now%.ahk
FileAppend, %vText%, *%vPath%, UTF-8
if InStr(A_ThisHotkey, 1) && FileExist(vPathAhk1U64)
	Run, "%vPathAhk1U64%" "%vPath%"
if InStr(A_ThisHotkey, 2) && FileExist(vPathAhk2U64)
	Run, "%vPathAhk2U64%" "%vPath%"
;MsgBox % "done"
Return
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

Re: conversion logic, v1 = -> v1 := -> v2, two-way compatibility

25 Feb 2017, 18:27

I suddenly realised, wait, is there a two-way compatible way to get the command line parameters?
Isn't it obvious? If A_Args is not set, use the v1 numeric vars.

Code: Select all

global Cmd_Args := A_Args
if !Cmd_Args {
    Cmd_Args := []
    Loop %0%
        Cmd_Args.Push(%A_Index%)
}
But actually, A_Args isn't a built-in variable. It is a normal variable, just like 0..%n% in v1, except that it is super-global by default.

Code: Select all

global A_Args
if !A_Args {
    A_Args := []
    Loop %0%
        A_Args.Push(%A_Index%)
}
Loop %0% in v2-alpha is currently equivalent to a double-deref which uses the expression 0 instead of a variable (so in effect, it's a single dynamic deref, and therefore causes an error only if it executes).
If I refer to MyLib_Func1 in a script, without including the MyLib script as a whole, and MyLib_Func1 refers to Func2 (where Func2 is in MyLib, but doesn't start with 'MyLib_'), that function will be able to run, despite not starting with 'MyLib'.
This shows that you lack a basic understanding of how #include and the auto-include mechanism work.

The presence of MyLib_Func1() in the script, and lack of a definition, cause the auto-inclusion of MyLib_Func1.ahk, or failing that, MyLib.ahk. The file is included, just like #include, except that it is put at the end of the script. AutoHotkey has no such capabilities that would allow it to extract one function from a file, or export only one name to the global "namespace".
By running a dummy function, it gives you access to all the other functions, that don't have a prefix.
It would be clearer to use #Include <MyLib>, although in that case it is included at that line, not necessarily at the end of the file.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: conversion logic, v1 = -> v1 := -> v2, two-way compatibility

25 Feb 2017, 20:33

Many thanks for the method. The %0% issue was giving me trouble. The following works:

Code: Select all

if A_Args
{
	Loop, % A_Args.MaxIndex()
		MsgBox % A_Args[A_Index]
}
else
{
	Loop, %0%
		MsgBox % %A_Index%
}
One method that looked promising, gave 'Error: This variable name starts with a number, which is not allowed', in AHK v2.

Code: Select all

vTemp := 0, vArg0 := %vTemp%
Loop, % vArg0
	vTemp := A_Index, vArg%A_Index% := %vTemp%, vOutput .= vArg%A_Index% "`r`n"
MsgBox % vOutput
Return
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
just me
Posts: 9423
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: conversion logic, v1 = -> v1 := -> v2, two-way compatibility

26 Feb 2017, 03:41

Who would need two-way compatibility? Once v2 will be released, all advanced script writers should switch to v2 and revise existing code manually. After the switch it might be helpful to have a script for automatic conversion to v1.1 for some time at best.
guest3456
Posts: 3454
Joined: 09 Oct 2013, 10:31

Re: conversion logic, v1 = -> v1 := -> v2, two-way compatibility

26 Feb 2017, 19:26

just me wrote:Who would need two-way compatibility? Once v2 will be released, all advanced script writers should switch to v2 and revise existing code manually. After the switch it might be helpful to have a script for automatic conversion to v1.1 for some time at best.
That's my opinion too, except I think the converter should be for v1 -> v2 (obviously ;) ).

just me
Posts: 9423
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: conversion logic, v1 = -> v1 := -> v2, two-way compatibility

27 Feb 2017, 09:58

guest3456 wrote:... except I think the converter should be for v1 -> v2 (obviously ;) ).
I don't think so. Existing v1.1 scripts will run unchanged on v1.1 as long as new Windows versions are compatible (I hope that once v2 is released v1.1 won't be maintained any more). The change to v2 should be used as an opportunity for a complete code revision. So only new scripts developed on v2 would need a converter if you want them to be able to run on v1.1 too. It might be more complex then a v1.1 -> v2 converter. ;)
guest3456
Posts: 3454
Joined: 09 Oct 2013, 10:31

Re: conversion logic, v1 = -> v1 := -> v2, two-way compatibility

27 Feb 2017, 10:20

just me wrote: The change to v2 should be used as an opportunity for a complete code revision.
That 'should' is quite an assumption, and one that i don't think most people will follow. But if it comes true, then yes, you're right

just me
Posts: 9423
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: conversion logic, v1 = -> v1 := -> v2, two-way compatibility

27 Feb 2017, 15:59

If someone really wants to convert an AHK 1.0 or 1.1.0 script to v2 without changes, why should it be supported?
guest3456
Posts: 3454
Joined: 09 Oct 2013, 10:31

Re: conversion logic, v1 = -> v1 := -> v2, two-way compatibility

27 Feb 2017, 16:39

I don't know what you're talking about

I do know that its tedious converting a big v1 script to v2 and having a converter speeds up the process tremendously

User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: conversion logic, v1 = -> v1 := -> v2, two-way compatibility

21 Mar 2017, 19:30

just me wrote:Who would need two-way compatibility?
I didn't insist on 'two-way compatibility' initially, here's my perspective:
- All my scripts and libraries, I use them daily, they will all need to be converted to AHK v2.
- Assume I don't care about two-way compatibility at all, what will it take to convert all my scripts, how difficult is it?
- After investigation, remarkably, it seems that everything I've written can be made two-way compatible (i.e. between the latest versions of AHK v1 and AHK v2). Lexikos et al. appear to have deliberately made it possible.
- The only exception, currently, is double quotes, doable, but quite ugly. Unless we bring `" to AHK v1, as "" is not possible in AHK v2, a lot of Chr(34)s are needed.
- I've been writing all sorts of syntax-checking and two-way compatibility scripts, including 32-bit/64-bit AHK to 32-bit/64-bit exe get/set GUI scripts. To be honest, the additional effort required to make a two-way compatible converter v. a one-way converter, is trivial.

- Now think of the advantages of two-way compatibility. The number one rule of programming is: avoid maintaining two versions of the same thing. Two-way compatibility negates this issue.
- Let's say I'm worried about compatibility issues, the only way to be sure is to test. As I'm going to have to convert my scripts at some point, and since two-way compatibility is as easy as one-way conversion, (and since converting my AHK v1 scripts now, such that I can't use them in AHK v1 would be stupid) ... I might as well convert all my code to make it two-way compatible now, and occasionally test it on AHK v2.
- Converting some/all of my code now, means I don't get a sudden rush of conversion to do at some point in the future. I can advise on sensible changes for AHK v1 and AHK v2. I can work out how to write code now that will be easier to convert or that won't need conversion. I can help people with conversion.
- I don't have to worry about what conversion problems I will have in future, I've proactively dealt with the problem.
- I have no particular personal desire to move to AHK v2 right now, neither do a vast proportion of users, there are currently no advantages for me. For example, the function renaming choices are good, but they can be done with custom functions in AHK v1 now. I did know though, I didn't want to hide my head in the sand like an ostrich, worried about, but not confronting the AHK v2 compatibility issues. Of having no idea what the extent of the conversion problems would be. I now have a list of roughly 20 problems, but the overall difficulty of conversion feels low. It was tough to take in 'everything you wanted to know about AutoHotkey v2 but were afraid to ask'.

- Btw it's stupid that people keep complaining about how inconsistent AutoHotkey's syntax is. My remedy would be to use function versions of commands, and add a new adjustable #Warn mode or script, that is more restrictive than the standard error checker, that says things like: don't use 'if a = b' without (round) brackets, or: don't use FileReadLine or StringMid.
- Btw changing syntax and renaming commands is one thing, but AutoHotkey should absolutely not be *removing* functionality like Progress, SplashImage, and String(Trim)Left/Right, the full cost of such changes, were they to be made, has not been fully worked out yet. Currently, few people even know of them. Also, the problems caused by redefining InStr and SubStr have been underestimated, 'StrRight' is scheduled for removal even though it is more needed now for AHK v2 than it ever was in AHK v1.
- I must admit that when I saw some of these changes being proposed, and the lack of the requisite debate, it was the first time I felt negatively about AutoHotkey (in half a decade or more) and concerned for its long-term future.
- I initially saw recreating GUI commands/functions as a bold challenge to take on, but ultimately, no, the associated disadvantages are complex and numerous, plus the detriment to convenience and ease of script sharing.
- Someone I greatly admire said:
Finally, people could continue to run such scripts with v1 if they really need those features.
I must admit that I've never done something in AHK v1, with the intention of not doing it in AHK v2.
- See this also:
The Future of the AutoHotkey Programming Language - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?t=6969
The transition from Perl 5 to 6 has resulted in most Perl programmers abandoning Perl, and most of what is left remains on 5.
...
The transition from Python 2 to 3 has resulted in most Python programmers remaining on 2.
- It is not a time to be naive and underestimate the difficulties involved in transition for beginners (and experts). It doesn't have to be too hard, and I'm doing everything I can to make it easier, for myself and for others. Apart from removing functionality, I welcome all the proposals, despite the enormous burden they entail for me.
- C and L and others, they have had very good taste, amongst other things, in syntax, and in function names, and changes to parameters, I've been so pleased how AHK has kept moving in the right direction and has been getting even all of the little details right. I'm very glad for example at how we open and close functions and that we don't need $ at the end of strings like in a related language that I also have great respect for.
- Btw we dodged a bullet here:
Oh please no, "<<" looks hideous.
==================================================
just me wrote:If someone really wants to convert an AHK 1.0 or 1.1.0 script to v2 without changes, why should it be supported?
- That's an interesting point, theoretically an AutoHotkey Basic script, that by definition uses a subset of AutoHotkey v2's features, should be compatible in AutoHotkey v2. Programming languages have to make changes to commands/functions sometimes, that's fine.
- Anyway, expecting to be able to run a script without any conversion being necessary is not what I advocated. What concerns me is the bridge, that the cliff edge between the last version of AHK v1 and AHK v2 is reduced.
- You could argue that maintaining backwards compatibility, holds back progression, but I appreciate that scripts that started out as two-way compatible will in due course become AHK v2 only. But there are specific advantages, during the transition, in making AHK v1 as forwards compatible as possible, think of it as AHK 'v1.9' to AHK v2 rather than AHK v1.1 to AHK v2.
- You can stuff as many things as you like into AHK v1 to ease the transition. My aim is to explore making AHK v1 scripts that will also work in AHK v2, and seeing what level of hackery, if any is needed. When you do all the cost-benefit analyses, two-way compatibility is the way to go, no doubt about it. A bit of careful thinking now, regarding the transition, will pay massive dividends.

==================================================
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: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: conversion logic, v1 = -> v1 := -> v2, two-way compatibility

21 Mar 2017, 20:43

Mainly for guest3456's attention:
I've basically completed the two-way compatibility conversion of 4 scripts:
Acc, AccViewer, (Anchor,) and iWB2 Learner.
So I'll be double-checking them, and looking at how to post them on GitHub.
An archive with the 4 new versions and the 4 old versions.

There's been a slight delay in release because after finally recreating WinGet, vPPath, ProcessPath, A, I realised there may be a hack to use the existing functions in AHK v1 and v2, explained below.

I'll also be bringing out my 'AHK commands as functions' update, which is for AHK v1 only, and which wraps AHK v1 commands as functions (using the AHK v2 function names) and which replicates functions new to AHK v2 like DirExist and DateAdd/DateDiff for AHK v1.

I have been thinking that I will make amended versions of AccViewer and iWB2 Learner:
- AccViewer would have 3 optional hotkeys, to focus the object/control/window under the cursor, this makes it easier to trace the paths.
- Options for both, to determine the relationship between clicking and setting the clipboard contents.
- Making iWB2 Learner work correctly even when the zoom is not set to 100%
Internet Explorer get element under cursor (show borders, show text) (any zoom percentage) - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=29458

==================================================

I thought that certain commands would have to be rewritten if true two-way compatibility was to be achieved, but I've since managed to come up with some hacks.

Using the AHK v1 command in both AHK v1 and AHK v2. But I'm ideologically against this, (continuing the usage of the old-style commands) so I won't be producing any further code along these lines.

- In AHK v1, the custom function 'FileSelectFile' does not interfere with the command FileSelectFile.
- In AHK v2, the custom 'FileSelectFile' also defines a command.
- We take advantage of %Func%() which is available in both AHK v1 and AHK v2.
- I was confused as to how a function could also define a command, but what it does is: *if something is returned* in a function, on the Return line, then that value becomes the first parameter, an output variable, in the command

Code: Select all

;using the AHK v1 command in both AHK v1 and AHK v2
FileSelectFile, vPaths, % "M", % A_Desktop, % "Open", % "Documents (*.txt)"
MsgBox % vPaths
Return

FileSelectFile(Options:="", RootDir:="", Prompt:="", Filter:="")
{
	Func := "FileSelect"
	Return %Func%(Options, RootDir, Prompt, Filter)
}
Using the AHK v2 command/function in both AHK v1 and AHK v2. However, this requires referring to the AHK v2 command/function by a different name, e.g. prefixing it with something.

- In AHK v1, the IsFunc fails, and FileSelectFile occurs.
- In AHK v2, ordinarily, 'try FileSelectFile' fails since FileSelectFile doesn't exist, you can do 'try %Command%', but that is not available in AHK v1. In AHK v2, IsFunc succeeds, ordinarily the FileSelectFile line would crash, since FileSelectFile doesn't exist in AHK v2, however, we define it as a dummy function (and hence command in AHK v2) that never gets called, which stops its presence as a command from crashing the script.
- Just in case a script tries to use the dummy function, we define it to send an error message and exit the thread.

Code: Select all

;using the AHK v2 command/function in both AHK v1 and AHK v2
vPaths := CustomFileSelect("M", A_Desktop, "Open", "Documents (*.txt)")
MsgBox % vPaths
Return

CustomFileSelect(Options:="", RootDir:="", Prompt:="", Filter:="")
{
	if IsFunc(Func := "FileSelect")
		Return %Func%(Options, RootDir, Prompt, Filter)
	FileSelectFile, vPaths, % "M", % A_Desktop, % "Open", % "Documents (*.txt)"
	Return vPaths
}

;this is a dummy function
FileSelectFile(Options:="", RootDir:="", Prompt:="", Filter:="")
{
	MsgBox % "Error: " A_ThisFunc " is deprecated."
	Exit
}
If there is a better hack that doesn't require the use of the additional prefixed function, that would be excellent to know about.

Btw something like 'try #NoEnv' would be very useful, I don't know if there's any workaround for that.

==================================================

I've read all the pages in the documentation about objects.
See:
jeeswg's objects tutorial (not yet complete) - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?t=29232

However, apologies, but I'm still unsure about ObjAddRef and ObjRelease. In case there's some really good examples somewhere. Although I can see a lot of other people are also having problems:
v2-changes
https://autohotkey.com/v2/v2-changes.htm
Most v1 scripts which use ComObjEnwrap(pdsp) (within the first few pages of Google results) used it incorrectly; i.e. they did not release their own copy of the pointer.
==================================================

Some quotes that highlight how confusing ObjAddRef/ObjRelease are:

ObjRegisterActive - Page 2 - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 8&start=20

When a remote script retrieves a reference to the object (via proxy), it's all handled by the (OS-provided) COM libraries. If the reference count increases by 3, obviously AddRef was called 3 times, probably because the COM libraries store 3 additional references. I don't think that would be documented anywhere, so basically, don't rely on the reference count.

ObjAddRef() / ObjRelease()
https://autohotkey.com/docs/commands/ObjAddRef.htm

This value should be used only for debugging purposes.

IUnknown::AddRef method (COM)
https://msdn.microsoft.com/en-us/library/ms691379.aspx

[OH IT'S REALLY IMPORTANT]
This method should be called for every new copy of a pointer to an interface on an object.

[OH IT TOTALLY DOESN'T MATTER]
This value is intended to be used only for test purposes.

[OH WAIT IS IT IMPORTANT?]
For example, if you are passing a copy of a pointer back from a method, you must call AddRef on that pointer. You must also call AddRef on a pointer before passing it as an in-out parameter to a method

==================================================

Are many people working on converting functions/libraries?
Btw guest3456, looking over many forum posts and comments, I'm very grateful for your advocacy for and work on conversion.
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 Development”

Who is online

Users browsing this forum: No registered users and 32 guests