your personal AutoHotkey style guide

Discuss Autohotkey related topics here. Not a place to share code.
Forum rules
Discuss Autohotkey related topics here. Not a place to share code.
john_c
Posts: 319
Joined: 05 May 2017, 13:19

Re: your personal AutoHotkey style guide

22 Jul 2019, 10:30

From my PM conversation with Flipeador:

Me:
In your Ahk2Exe on GitHub you sometimes use something like

Code: Select all

; https://github.com/flipeador/Ahk2Exe/blob/master/Ahk2Exe.ahk#L457
if (Var != "")
but sometimes

Code: Select all

----
; https://github.com/flipeador/Ahk2Exe/blob/master/Ahk2Exe.ahk#L546
if (Var)
Could you explain, is there any difference between them? And why you use slightly unusual if (Var != "") instead of if (Var)?
Flipeador:
In AutoHotkey it is true that an empty string is interpreted as FALSE, but for me this is not appropriate. So, if a function returns an empty string to indicate error, I prefer to use if (var == ""), it's more explicit and clear. On the other hand, if the function returns zero in case of error, I use if (var == 0) or if (!var). Also AHK interprets a number in a string just like a pure number, which I disagree with as well (when used with if strnum == num). I never handle an empty string as FALSE.

This is true on v2.0-a103-56441b52:

Code: Select all

MsgBox "0x00009" == 9
Last edited by john_c on 11 Sep 2019, 22:03, edited 1 time in total.
john_c
Posts: 319
Joined: 05 May 2017, 13:19

Re: your personal AutoHotkey style guide

22 Jul 2019, 15:25

@jeeswg
If/else styles, any opinions?

Code: Select all

func()
{
    if (...)
        return True
    else
        return False
}

Code: Select all

func()
{
    if (...)
        return True
    return False
}
See here:

https://softwareengineering.stackexchange.com/questions/157407/best-practice-on-if-return
User avatar
jeeswg
Posts: 6828
Joined: 19 Dec 2016, 01:58
Location: UK

Re: your personal AutoHotkey style guide

31 Aug 2019, 17:06

HUNGARIAN NOTATION
aeiklmr wrote: This is strange. I am Hungarian and did a very similar thing, but I've never heard about this thing before. :shifty:
@aeiklmr: Hehe, it's funny when things like that happen. Hungarian notation is great. Apparently 'English muffins' are a thing.

NOT ENDING FUNCTIONS WITH IF/ELSE
@john_c: Great addition. Thanks.

Code: Select all

;NO (but logical):
func()
{
	if cond
		return 1
	else
		return 0
}

;YES (probably better overall):
func()
{
	if cond
		return 1
	return 0
}
DLLCALL (AND QUOTES)
Since AHK v2 'Disabled unquoted arg and return types for DllCall', I've revised how I do DllCall.
Using DllCall for dll functions:

Code: Select all

;notes from my JEE_TidyDllCall function:
;[YES, include name] n: always include dll name (else omit comctl32/gdi32/kernel32/user32)
;[NO, i.e. omit .dll] x: always include .dll e.g. 'DllName.dll\Func' (else 'DllName\Func')
;[NO, i.e. omit Int] r: always include return type (else omit Int)
;[YES, use pairs] p: use pair style e.g. 'T1,A1, T2,A2' (else 'T1, A1, T2, A2')
;[YES, use quotes, was no] q: use quotes style e.g. "Int" (else Int)
;[YES, use *, was no] s: use star style e.g. Int* (else IntP)

;before: I omitted quotes for brevity
;after: changed to use quotes because:
;AutoHotkey v2 alpha (UPDATES) - Page 3 - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=37&t=2120&p=275703#p275703
;'Disabled unquoted arg and return types for DllCall.'

;before: I used XXXP style for brevity
;after: since now using quotes, XXX*/XXXP are of equal length,
;and XXX* is more standard than XXXP

;YES:
;MB_OK := 0x0
DllCall("user32\MessageBox", "Ptr",0, "Str","text", "Str","title", "UInt",0x0)

;NO (opposite):
;MB_OK := 0x0
DllCall("MessageBox", Ptr, 0, Str, "text", Str, "title", UInt, 0x0)
DLLCALL AND INTERFACES
Using DllCall for interface methods:
The key point is that I now always include 'interface::method' as a comment.
Adding in the comments to my main scripts/libs, was a lot of work, but very worthwhile.

Code: Select all

;CM_ENUM_VISIBLE := 0x2
vCountCol := 0
DllCall(NumGet(NumGet(pCM+0)+5*A_PtrSize), "Ptr",pCM, "UInt",0x2, "UInt*",vCountCol) ;IColumnManager::GetColumnCount

;or, if using a VTable function:
;CM_ENUM_VISIBLE := 0x2
vCountCol := 0
DllCall(VTable(pCM, 5), "Ptr",pCM, "UInt",0x2, "UInt*",vCountCol) ;IColumnManager::GetColumnCount
VTable(ptr, n)
{
	return NumGet(NumGet(ptr+0), n*A_PtrSize)
}
FILEAPPEND
FileAppend, I always use 3 parameters for clarity:

Code: Select all

FileAppend,, % vPath, CP1252 ;create an empty 0-byte file
FileAppend, % vOutput "`r`n", % "*" vPath, UTF-8 ;create/append to a text file
BRACES: MINIMUM/OPTIMUM/MAXIMUM
Braces(/indentation):
Before: use the minimum number of braces.
After: always use braces apart from for one-liners.
Adding in the braces to my main scripts/libs, was a lot of work, but very worthwhile.
Basically I searched for two consecutive lines starting with control flow statements that affect indentation (note: 'else XXX' and 'try XXX' one-liners do not affect indentation):
vIsMatch := !RegExMatch(vTemp, "i)^(else[ `t]|try[ `t])") && RegExMatch(vTemp, "i)^(else|if|Loop|while|catch|finally|for[ `t]|try)")
[note: 'FormatTime', false positive for 'for']

Code: Select all

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

;before:
Loop 3
	if cond
	{
		action1()
		action2()
		action3()
	}

after:
Loop 3
{
	if cond
	{
		action1()
		action2()
		action3()
	}
}

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

;before:
Loop 3
	if cond
		action()

;after:
Loop 3
{
	if cond
		action()
}

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

;before:
Loop 3
	if cond1
		Loop 3
			if cond2
				action()

;after:
Loop 3
{
	if cond1
	{
		Loop 3
		{
			if cond2
				action()
		}
	}
}

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

;before:
Loop 3
	if cond1
		action1()
	else if cond2
		action2()
	else if cond3
		action3()
	else
		action4()

;after:
Loop 3
{
	if cond1
		action1()
	else if cond2
		action2()
	else if cond3
		action3()
	else
		action4()
}

;==================================================
[EDIT:] Updated vIsMatch RegEx line.
Last edited by jeeswg on 15 Sep 2019, 10:14, edited 1 time 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
User avatar
Chunjee
Posts: 189
Joined: 18 Apr 2014, 19:05
GitHub: Chunjee

Re: your personal AutoHotkey style guide

09 Sep 2019, 22:10

jeeswg wrote:
31 Aug 2019, 17:06
Braces(/indentation):
Before: use the minimum number of braces.
After: always use braces apart from for one-liners.
My homie :thumbup: :thumbup: :thumbup:
User avatar
jeeswg
Posts: 6828
Joined: 19 Dec 2016, 01:58
Location: UK

Re: your personal AutoHotkey style guide

15 Sep 2019, 10:21

@Chunjee: Hehe. Thanks. I've seen the idea of *always* using braces (including for one-liners) discussed. My idea is to 'almost always' use braces, with the exception of one-liners, a sort of halfway house, but I don't recall seeing that approach discussed anywhere, have you? Are you using the same principles as me, or something slightly different? Thanks.
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
Chunjee
Posts: 189
Joined: 18 Apr 2014, 19:05
GitHub: Chunjee

Re: your personal AutoHotkey style guide

15 Sep 2019, 11:22

Wish I could find it again but some article I read a while back convinced me that code comprehension was much more valuable than neat tricks and clever code. The basic argument being that when working with a group, or even a later version or yourself; being able to quickly understand what is going on an why is more valuable than using hacks to get it done in less lines. For this reason, I like very straightforward solutions, even if they are a few milliseconds slower. I don't really care that something is faster for the CPU if it takes me 10 mins to figureout what is going on when I open it again a year from now.

Other inspirations:
https://12factor.net/
https://www.zenprogrammer.org/en/10-rules-of-a-zen-programmer.html


Overall I would say that I like your style and principles a lot. They mirror what I've come to know on my own or through other sources. Perhaps we are on different paths to the same truths.
User avatar
nnnik
Posts: 4276
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: your personal AutoHotkey style guide

15 Sep 2019, 11:51

Which brings us back to the discussion of practices.
Something that I do regularily or many others do regularily might be completely foreign to other people.
No member will ever be able to completely understand all other peoples styles - a rule for good practices probably can only be enforced by the developers themselves simply by going in one direction and disregarding the other.
Though in general its a waste of time to worry about Allman vs. K&R because it matters very little in practice.
A real argument for K&R is that many advanced languages force you or advise to use it.
Going with K&R would make it easier for those to swap languages back and forth.
Same goes for most other considerations in this topic.
Recommends AHK Studio
SOTE
Posts: 789
Joined: 15 Jun 2015, 06:21

Re: your personal AutoHotkey style guide

16 Sep 2019, 05:38

jeeswg wrote:
15 Sep 2019, 10:21
@Chunjee: Hehe. Thanks. I've seen the idea of *always* using braces (including for one-liners) discussed. My idea is to 'almost always' use braces, with the exception of one-liners, a sort of halfway house, but I don't recall seeing that approach discussed anywhere, have you? Are you using the same principles as me, or something slightly different? Thanks.
I'm on the side of always use braces (and indentation), because I'm not concerned about typing speed as much as I rather always be able to clearly see and understand what the code is doing. When it comes to indentation, prefer tabs, as spaces can create more of a mess or confusion. Especially when it comes to troubleshooting or coming back weeks or months later to review or update code. A lot of styles create a big mess of squashed together or convoluted code, where the programmer is trying to impress people that are not there or make themselves feel more clever with the way that the code "looks" (form over function), but this can cause unnecessary errors or makes it hard for others (or even themselves later on) to read.

Also, when it comes to other programming languages, one should be careful with assuming that C style or C family languages rule all. In languages like Object Pascal, Lua, and Python (for example) how they are written is a bit different. And these are reasonably popular languages. With Object Pascal, using braces all of the time (from the C family language), even for one-liners can arguably make "translating" between languages easier. As it's easier to identify blocks of code or nested loops. But, Object Pascal does allow you to omit "Begin" and "End" (equivalent to { }) for one-liners, like you can do in C family languages.
john_c
Posts: 319
Joined: 05 May 2017, 13:19

Re: your personal AutoHotkey style guide

02 Oct 2019, 08:10

Any opinions about Try/Catch vs. ErrorLevel?

* In some cases Try/Catch is the only possible option.
* ... and sometimes the only possible option is ErrorLevel.

These cases are out of scope of my question. But what about the cases when both of these ways can accomplish the task? Is one way is better than another?

Code: Select all

Try
  FileCopy, a.txt, % A_ProgramFiles
Catch
  MsgBox,,, % "There was a problem while copying."

Code: Select all

FileCopy, a.txt, % A_ProgramFiles
If (ErrorLevel != 0)
  MsgBox,,, % "There was a problem while copying."
User avatar
jeeswg
Posts: 6828
Joined: 19 Dec 2016, 01:58
Location: UK

Re: your personal AutoHotkey style guide

02 Oct 2019, 20:49

ERROR HANDLING

- Are there are crossover examples?
- It throws on an error (throw, handled by: try/catch/finally/OnError) or it doesn't (indicate failure by one of: function return value/function ByRef output variable/ErrorLevel/special variables for convenience like A_MsgBoxResult which was at one point in AutoHotkey v2).
- A_LastError, which uses the Winapi function GetLastError, might be set, whether you throw or don't.
- Using either/all of those is fine, but I would want to write scripts where using ErrorLevel is not necessary.

- In the past, AHK didn't have 'throw', I wrote all of my functions to return error values (via return values or via ByRef output variables), and not use throw. I got used to *thinking carefully* and *taking responsibility*. But, safety is probably the most important thing in programming, and I'm getting used to the idea of 'the safer the better'.
- Also, code commonly gets revised, and it's easy to introduce new bugs, so, 'safety first'.

- I'm neutral re. try/catch/finally etc, I haven't minded using them, e.g. they're commonly used with Internet Explorer, MS Excel and in the Acc.ahk library.
- Perhaps it's useful, when using operators/mathematical functions, to throw versus return blank strings. But then again, the entire formula resolving to a blank string, if there was at least one error, might be fine.
- Throw could encourage lazy coding: instead of writing proper code to handle errors, you just let them occur with the option to terminate the script or let it run.
- Although you could say throw makes things secure, guarding against amateur or lazy coders: any error must be explicitly handled by the code, or the script is terminated. That said, there may possibly be unforeseen circumstances, even for the expert.

- There may be a disadvantage in forcing a script to end, for example, some minor error (which may not even strictly be an error).
- E.g. AHK is being increasingly strict about what it considers an error. I think this is a good thing. However, I wrote my scripts to meet the old standards, and so now my scripts could end unexpectedly, and I'd lose my data. If error messages provide an option that allows you to keep running the script, then there is no problem.
- E.g. you could have a script: for each key in obj.mykey, append the key's value to a string. Before, under the old rules, if 'mykey' didn't exist, you'd end up with a blank string, now, you get an error message and the script terminates.
- E.g. before, you could depend on the value of an undefined key being a blank string, now you have to add handling in case the key doesn't exist.
- (If my script is about to be forcibly but unnecessarily terminated, I might try and grab any data from the address space.)

- Perhaps the best answer is: it's OK to use either way (throw/don't throw). But throw gives you error messages, thus more safety, however, throw without the option to let the script continue running, could be a major problem. Either way, if you knew something could have catastrophic consequences, consider showing an error message and ending the thread/process.
- One thing to consider, if your function is in a library, the function's error handling could/should match the style of error handling of any other functions.

- There was an interesting discussion here:
ErrorLevel - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=37&t=49733

- [EDIT:] My current best advice: when any problem, that is not explicitly handled, occurs, show an error message, an error message that can be ignored. If it's a serious error, show an error message and end the thread/process. So, optional exit versus forced exit.
Last edited by jeeswg on 10 Nov 2019, 14:01, edited 1 time 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
john_c
Posts: 319
Joined: 05 May 2017, 13:19

Re: your personal AutoHotkey style guide

03 Oct 2019, 02:02

@jeeswg From what you said, it seems that the main advantage of Try/Catch is the use of Throw. We cannot use Throw without them.

This is a good point, I haven't considered it before.

Edit, few days later:

> We cannot use Throw without Try/Catch.

Of course, it's not correct. We can.

Code: Select all

Var := True
if (Var)
    throw "Something went wrong"
A little confusing that nobody mentioned my "stupidity".
Last edited by john_c on 05 Oct 2019, 17:04, edited 2 times in total.
john_c
Posts: 319
Joined: 05 May 2017, 13:19

Re: your personal AutoHotkey style guide

03 Oct 2019, 15:51

Another case to take into account:

* normal loops,
* normal loops with Until,
* While-loops.

Code: Select all

Loop, 5
{
    i += 1
    MsgBox,,, % i
}

Code: Select all

Loop
{
    i += 1
    MsgBox,,, % i
} Until i = 5

Code: Select all

While i < 5
{
    i += 1
    MsgBox,,, % i
}
Last edited by john_c on 04 Oct 2019, 03:00, edited 1 time in total.
User avatar
jeeswg
Posts: 6828
Joined: 19 Dec 2016, 01:58
Location: UK

Re: your personal AutoHotkey style guide

03 Oct 2019, 16:55

- I tend to find that the while-condition or until-condition tend to bring in a bit of uncertainty to code. You could get off-by-one errors as a result.
- (I use 'while' occasionally, I never use 'until'.)
- I find that using 'Loop' (indefinite) or 'Loop count', with an if-statement to cause the break, gives more certainty.
- (For similar reasons, I prefer to avoid clever uses of i++ or ++i in elaborate one-liners.)

- Bearing in mind that different programming languages do things differently, the more simple and explicit, the better. (However, if a language's syntax is simple/explicit, but too restrictive, e.g. Python at times, this is also bad. Better to give people options, and reasons to do things a certain way.)

- (I find it better to avoid using 'break 2', to break out of the current loop, and the outer loop. This is because C++ doesn't allow it, and I like code to be easily translatable, however I think the 'break n' concept is fine. Instead, I set a variable in the inner loop to 1, e.g. vDoBreak, and check if it equals 1 in the outer loop.)

- I tend to like code to match the way I thought of it, sometimes a higher-level concept (1 variable swap v. 3 variable assignments), sometimes a lower-level concept (check the condition).
- (Doing things in a slightly lower level way tends to match how ASM does it. E.g. in this example, using an if-statement rather than some 'while' or 'until' concept. Btw ASM jumps to a named label rather than use some 'loop' concept.)

- I find the following 4 approaches to be acceptable. Cheers.

Code: Select all

i := 0
Loop
{
	i++
	MsgBox, % i
	if (i = 5)
		break
}

Loop
{
	i := A_Index ;1-based index
	MsgBox, % i
	if (i = 5)
		break
}

i := 0
Loop 5
{
	i++
	MsgBox, % i
}

Loop 5
	MsgBox, % A_Index
[EDIT:] Looking through my library functions, I'm tempted to replace the approx. two dozen instances of 'while' with Loop and if-condition-and-break. Apart from in occasional trivial examples like this:

Code: Select all

	while oWB.busy || oWB.readyState!=4 || oWB.document.readyState!="complete" ;READYSTATE_COMPLETE := 4
		Sleep(10)

	while InStr(vText, "**")
		vText := StrReplace(vText, "**", "*")
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: 4002
Joined: 17 Jul 2016, 01:02
Contact:

Re: your personal AutoHotkey style guide

04 Oct 2019, 03:42

john_c wrote:
03 Oct 2019, 15:51

Code: Select all

Loop
{
    i += 1
    MsgBox,,, % i
} Until i = 5

Code: Select all

While i < 5
{
    i += 1
    MsgBox,,, % i
}
These aren't equivalent.
until wrote:The expression is evaluated once after each iteration
while wrote:The expression is evaluated once before each iteration.

jeeswg wrote:- I find that using 'Loop' (indefinite) or 'Loop count', with an if-statement to cause the break, gives more certainty.
until wrote: Loop Until is shorthand for the following:

Code: Select all

Loop {
    ...
    if (Expression)
        break
}
However, Loop Until is often easier to understand and unlike the above, can be used with a single-line action.

Also note,
Until can be used with any Loop or For.
Cheers.
User avatar
jeeswg
Posts: 6828
Joined: 19 Dec 2016, 01:58
Location: UK

Re: your personal AutoHotkey style guide

04 Oct 2019, 12:16

- @Helgef: I think john_c was correct to describe the 2 examples as equivalent, i.e. they both output the numbers 1 to 5. (And as a bonus, they both leave i equal to 5 after the loop.)

- Well, the documentation states this, but the documentation is wrong (IMO):
However, Loop Until is often easier to understand
- Using your quotations:
until: The expression is evaluated once after each iteration
while: The expression is evaluated once before each iteration
my example: The expression is evaluated once *during* each iteration (unless it is bypassed, e.g. by break/continue)
- I think that the *during* part, makes it far clearer. Also, you might be unsure as to whether 'continue' bypasses the until-condition or not. (It's these little uncertainties that add up, hence my overall conclusion.)
- Thanks for your comments and useful quotations. Cheers.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
john_c
Posts: 319
Joined: 05 May 2017, 13:19

Re: your personal AutoHotkey style guide

11 Oct 2019, 12:09

Click and ControlClick:

Can we say that one of them is better for average not-gamer?
User avatar
jeeswg
Posts: 6828
Joined: 19 Dec 2016, 01:58
Location: UK

Re: your personal AutoHotkey style guide

11 Oct 2019, 18:22

- ControlClick has these advantages: you can specify the hWnd, and (generally speaking), the window doesn't have to be active/visible.
- (Click works on the visible window at the specified point, you risk clicking the wrong window, if the window at that point changes.)
- So, if ControlClick works, I'd use that, otherwise Click.
- Every game/piece of software is different regarding whether ControlClick/Click/PostMessage/Acc (accDoDefaultAction)/other approaches will work. Also, using ControlFocus first, may make a difference.
Last edited by jeeswg on 11 Oct 2019, 18:39, edited 1 time 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
john_c
Posts: 319
Joined: 05 May 2017, 13:19

Re: your personal AutoHotkey style guide

11 Oct 2019, 18:37

@jeeswg Thanks. The question about clicks interested me for a long time.
john_c
Posts: 319
Joined: 05 May 2017, 13:19

Re: your personal AutoHotkey style guide

11 Oct 2019, 19:12

Update:

One advantage of Click over ControlClick is that we have a possibility to check if the coordinates are correct, and how precisely they are specified.

When we use ControlClick, the mouse cursor is moved "invisibly" and therefore there is no such possibility. (Of course, we can use additional MouseMove to check the correctness of the coordinates.)
john_c
Posts: 319
Joined: 05 May 2017, 13:19

Re: your personal AutoHotkey style guide

16 Oct 2019, 21:47

Any opinions about Switch vs If/Else?

Just for the record: I never worked with switches before. This thing is completely new for me. One article that I found on the websays that
if-else better for boolean values: If-else conditional branches are great for variable conditions that result into a boolean, whereas switch statements are great for fixed data values.

(source: https://www.geeksforgeeks.org/switch-vs-else/)
It seems there are great answers here at https://www.quora.com/Why-do-we-use-switch-instead-of-else-if, but, to be honest, they are too complicated. It seems they are intended for people who already worked with switches a lot.

Another links that looks useful:

* https://stackoverflow.com/questions/680656/what-is-the-difference-between-if-else-and-switch.
* https://www.codecademy.com/forum_questions/5429a1a19c4e9d6246004d1a (the example looks good)

Return to “General Discussion”

Who is online

Users browsing this forum: No registered users and 2 guests