Page 1 of 1

Understanding AutoHotkey

Posted: 21 May 2016, 18:25
by func
My theory is that the main difference between truly masterful AutoHotkey scripters (of which there are only a few) and casual and intermediate scripters is the fluent understanding of the entire range of useful AutoHotkey syntax and vocabulary.

Programming/conversation design patterns and efficient structures all evolve quickly and naturally once you fully understand any language.

I derive this insight from how I learned and applied my most fluent language, English, which I use every day.
In order to write, read, and formulate meaningful English conversations I rely on a constantly accessible and vast database of English syntax and English vocabulary. Spellcheck is my only English IDE feature; I don't need to know how to spell all words I merely need to know that useful words exist, how to approximately construct such words, and where to use such words.

All higher level English design patterns, such as writing a novel, a short how-to guide, formulating an interview questionnaire, writing a blog post, writing a book review, etc. come naturally by seeing first how others use such patterns, and then making my own unique instances of these patterns using the same building blocks - the English language syntax and vocabulary. My theory is that AutoHotkey (and any other language) patterns can be instantiated much the same way.

In order to become fluent in AutoHotkey and create useful and advanced AutoHotkey conversations with computers I need to be able to have a deep understanding of the syntax and vocabulary of AutoHotkey, so much so that there are basically no major "what-ifs" or "vocabulary gaps" during coding that stop my flow of attention. After a coherent plan has been formulated, much like a coherent plan about what you want to say when writing a book or movie review, there should be almost no writers block when writing, but merely quickly refactoring/restructuring as I go along to optimize the conversation, only pausing to read/reread some code already written, just like when using English fluently.

Even when other people write poorly formatted or structured English, I can always decipher exactly what each word is, even if I don't derive the contextual meaning. Reading AutoHotkey code I cannot yet do this, even reading the documentation I cannot yet do this.
Therefore I will begin by systematically exploring the AutoHotkey syntax and vocabulary using commented tests written in AutoHotkey. It will be a slow process spanning over one or two months. I suspect that I will have to update, extend, restructure, and refactor the comments as well as the test code many times over this period.

Here is what I started with today. My systematic process is to copy pages or partial pages from the documentation into SciTE4AutoHotkey, break each concept down into its elemental parts, and tested each elemental part in order to link each concept in the documentation with a behavior I will come to expect. The collection of all of these concepts linked to all of these behaviors will result in an ever growing understanding of AutoHotkey.

I highlight each snippet in SciTE4AutoHotkey, right click, and "run selection" to test each block as I'm writing them.

Taken partially from: https://autohotkey.com/docs/Variables.htm

Code: Select all

;~ Variable types: AutoHotkey has no explicitly defined variable types. However, a variable containing only digits (with an optional decimal point) is automatically interpreted as a number when a math operation or comparison requires it. (To improve performance, numbers are cached internally to avoid conversions to/from strings.)
a := 5 ; the variable "a" contains only a digit, but is not interpreted to be a number yet
b := a + 5 ; the variable "a" is required for a math operation (a + 5) so it is interpreted to be a number type variable because it's used in a math operation on this line
msgbox % "b is equal to: " . b . "`nThis is because the variable ""a"" was interpreted as a number, and added to 5 (b := a + 5) to evaluate to 10."
if a = 5 ; the variable "a" is required for a comparison (if a = 5) on this line, since the variable "a" contains only digits, it is interpreted as a number
{
	msgbox % "yes, the variable ""a"" is equal to 5!"
}
else
{
	msgbox % "no, the variable ""a"" is not equal to 5!"
}

; Here is an example where a variable does not contain only digits, so it's not interpreted as a number type variable when used in math operations or comparisons.
a := 5grams ; the variable "a" contains contains a digit, but also non-digits : it is not interpreted yet
b := a + 5 ; the variable "a" is required for a math operation (a + 5) but "a" does not contain only digits, so it's not interpreted as a number, the math operation fails silently and "b" evaluates to nothing (empty)
if a = 5 ; the variable "a" is required for a comparison (if a = 5) on this line, since the variable "a" contains only digits, it is interpreted as a number
{
	msgbox % "yes, the variable ""a"" is equal to 5!"
}
else
{
	msgbox % "no, the variable ""a"" is not equal to 5!"
}


;~ Variable scope and declarations: With the exception of local variables in functions, all variables are global; that is, their contents may be read or altered by any part of the script. 
a := "test"
gosub MyLabel
return
MyLabel:
msgbox % a ; the variable "a" is found because variables created outside functions are accessible everywhere in the script except inside functions.
return

;~ To access variables created outside functions and use them inside functions they must be declared global variables outside of functions.
global a := "test"
msgbox % myFunction()
myFunction() {
	b := a . " worked"
	return b
}

;~ Alternatively, functions themselves can be declared global so that they can use variables created outside of functions.
a := "test"
msgbox % myFunction()
myFunction() {
	global ; this function is declared a global function by placing "global" on the first line inside of the function
	b := a . " worked"
	return b
}

;~ Except where noted on the functions page, variables do not need to be declared;


;~ Variables come into existence simply by using them (and each variable starts off empty/blank).
if (a = "") ; the variable "a" comes into existence simply by using it in a comparison
if b = ; the variable "b" comes into existence simply by using it in a comparison
c := ; the variable "c" comes into existence simply by using it when you assign it (even assign it to contain nothing as in this example)
msgbox % "a: " . a . "`nb: " . b . "`nc: " . c . "`nThe variables came into existence, but their contents starts off empty/blank."


;~ Variable names: Variable names are not case sensitive (for example, CurrentDate is the same as currentdate).
CurrentDate := "December 5th, 1805"
currentdate := "January 6th, 1906" ; The currentdate is the same as CurrentDate, so CurrentDate/currentdate both contain "January 6th, 1906" on the second line.
msgbox % "currentdate: " . currentdate . "`nCurrentDate: " . CurrentDate . "`ncURRENTdATE: " . cURRENTdATE

;~ Variable names may be up to 253 characters long and may consist of letters, numbers and the following punctuation: # _ @ $
abc := "test 1"
123 := "test 2"
#a# := "test 3"
_b_ := "test 4"
@c@ := "test 5"
$d$ := "test 6"
msgbox abc: %abc% `n123: %123% `n#a#: %#a#% `n_b_: %_b_% `n@c@: %@c@% `n$d$: %$d$%


Re: Understanding AutoHotkey

Posted: 30 May 2016, 19:04
by jesushh
Interesting post.
I like this stuff, how we learn and how we can improve this process.

From my (short) experience I would summarize that instead of theory, or using intelligence for guessing things....just do, do, do, try , try, try code.
And you expressed in a very comprehensible way, just trying many possibilities for every single concept in the docs.
By doing so, I guess the programmer gain an understanding of every command in a very "complete" way, instead of if you just use what is in the docs and it seems "it works".

I agree with the consideration that if you don't know part of the syntax/elements of the language it will be impossible to build scripts of certain level of mastery. This is obvious to some extent, though, if objects for example provide a much better way to do whatever you are doing; but you don't know them, of course you don't "understand Autohotkey" enough to use them. Maybe I am misunderstanding this point of yours :)

Thank you!

Re: Understanding AutoHotkey

Posted: 09 Jun 2016, 14:55
by evilC
Some insightful words there.

AHK is quite a special case, insofar as it has two syntax styles to wrap your head around and a set of rules that govern which of the two apply.

Consider the following code:

Code: Select all

#SingleInstance,Force

var := "hello"
a := "Hello"

if a = var		; False. Not expression syntax. Comparing variable a with "var"
	msgbox % "a = var is true"

if (a == var)	; False. Expression syntax, but case sensitive compare
	msgbox % "(a == var) is true"

if (a = var)		; True. Expression syntax, case INsensitive compare
	msgbox % "(a = var) is true"
Personally, I always try to use Expression Syntax and learn how to force expression syntax for any given command or parameter.
So you picked the absolute best page to start on IMHO. Understand this aspect of AHK and you will be well set up to get the most out of it.

Re: Understanding AutoHotkey

Posted: 10 Jun 2016, 12:55
by victorel
I think equality comparison, by default, should mean "identical", and there should be a single symbol for that (either = or ==).
In case of strings, then case sensitive comparison. If the user needs case insensitive, then there should be a parameter or something to be added for this.

Then there will be less confusion.

Re: Understanding AutoHotkey

Posted: 10 Jun 2016, 13:37
by tidbit
I have never seen any confusion over Case when comparing. Making it more strict by default would probably cause a problem where there is none

If the user needs case sensitive, then there should be a parameter or something to be added for this. (oh wait, there already is. == does that :P one = for simple match (it's simple to type and read, it has simple rules) and == for fancy match (it looks fancy and different, fanciness indicates more strict rules to follow))

Also, great first and only post, func.

Re: Understanding AutoHotkey

Posted: 10 Jun 2016, 13:39
by evilC
I agree with tidbit. This is one quirk of AHK that I actually quite like.

Re: Understanding AutoHotkey

Posted: 10 Jun 2016, 17:13
by victorel
But you agree it's a quirk :)

Re: Understanding AutoHotkey

Posted: 10 Jun 2016, 17:48
by tidbit
afaik, no language I have used has "case sensitive first". though, I've only used maybe 5.
it's usually always = to 'compare' and == or === to 'case sensitive compare'. I don't see it as a quirk.

Re: Understanding AutoHotkey

Posted: 11 Jun 2016, 08:40
by victorel
Really?
I've mostly used Matlab in the past, and there it's just "==" for all comparisons (and means case sensitive). Besides, they have string specific functions like strcmp() and strcmpi(), for case sensitive, and case insensitive.

In Python, there a single equality operator: "==" , and means case sensitive. For case insensitive comparison, one has to transform the strings first : http://stackoverflow.com/questions/3194 ... -in-python

C++, similar to python, http://stackoverflow.com/questions/1163 ... rison-in-c

Javascript, == for general equality, including string sensitive comparison http://www.w3schools.com/js/js_comparisons.asp , http://www.w3schools.com/js/tryit.asp?f ... omparison1

And here's a wikipedia list of string equality operators: https://en.wikipedia.org/wiki/Compariso ... 9#Equality . Languages often use a second operator to include type comparison as well, not for case sensitivity.

From above, my conclusion is that the common / normal in languages is that the general equality operator (be it = or ==, depending on language) applies to strings as case Sensitive comparison. And that makes sense, as Equality means equality in value (not approximately equal, or similar or equivalent etc). While to get case insensitivity, languages would use either other means like functions, or a different operator.

And in Autohotkey, it's the other way around. :wtf:

Maybe this should be in the Wish List or Autohotkey v2 / future forum?

Re: Understanding AutoHotkey

Posted: 11 Jun 2016, 14:23
by Xtra
There is nothing stopping you from using == for everything is there?
There is nothing in the docs saying one is the default and one is an option.I don't see the issue here.

Re: Understanding AutoHotkey

Posted: 11 Jun 2016, 20:39
by victorel
True, nothing stops me from using my favorite symbol, and you from using yours. And same things goes with a number of other things syntax-related in Autohotkey.
However, this is cumulative, and what that leads to overall, is:
1. Harder to learn the language for beginners, both because it is nonstandard compared to most other popular languages, and simply because it's, well, more to memorize.
2. Harder to understand code written by other people.

By the way, similar suggestions regarding = and == were expressed by this person here https://autohotkey.com/boards/viewtopic.php?f=13&t=6969 , who is way-way-way more computer science literate than I am. Also, general stuff regarding familiarity, consistency, elegance of any programming language.

Re: Understanding AutoHotkey

Posted: 12 Jun 2016, 09:39
by Xtra
I don't have a favorite symbol i just use what's appropriate for what i'm trying to do.

1. The only thing making it difficult for people to learn AHK is all the old commands and backwards compatibility left in to not break older scripts.
AHK is one of the easiest languages to learn, definitely very forgiving and you don't need to memorize every little thing there is the help file for that.(Same goes for all languages)

2. If you write code sloppy and without comments etc of course that's going to make it harder for anyone to understand it.

Every language has differences in syntax. aka quirks...Nothing new here.

Re: Understanding AutoHotkey

Posted: 13 Jun 2016, 09:36
by victorel
Well, I did not mean to say that Autohotkey is a hard language, but that it could be made easier to learn for the beginner by removing redundancies and quirks.
2. If you write code sloppy and without comments etc of course that's going to make it harder for anyone to understand it.
I think you misunderstood my message there. From the beginner's perspective, another thing that makes it harder is that he has to learn several ways of doing things (like several syntaxes for assignment, equality testing, etc, and both commands AND functions syntax) not because he cannot use just one of them, but because when he read's other people's code, he encounters them there. Plus, even the tutorials he is learning from are not sticking to strictly one variant of syntax available.

Of course, the more advanced users may not have any trouble with this, as they already know most variants.
Every language has differences in syntax. aka quirks...Nothing new here.
Sure, about every other language has its own quirks and faults, but I did not think that's an excuse not to try to get better.
So it remains up to developers to decide whether they want to pay more attention to newbies' wishes.

Re: Understanding AutoHotkey

Posted: 13 Aug 2016, 10:09
by lmstearn
Here's Func's code without the spaces. Just renamed a function, put the label at the end, the not existing vars at the start, and ran the whole lot from NPP. :bravo:

Code: Select all

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.


;~ Except where noted on the functions page, variables do not need to be declared;

;~ Variables come into existence simply by using them (and each variable starts off empty/blank).
if (a = "") ; the variable "a" comes into existence simply by using it in a comparison
if b = ; the variable "b" comes into existence simply by using it in a comparison
c := ; the variable "c" comes into existence simply by using it when you assign it (even assign it to contain nothing as in this example)
msgbox % "a: " . a . "`nb: " . b . "`nc: " . c . "`nThe variables came into existence, but their contents starts off empty/blank."


;~ Variable types: AutoHotkey has no explicitly defined variable types. However, a variable containing only digits (with an optional decimal point) is automatically interpreted as a number when a math operation or comparison requires it. (To improve performance, numbers are cached internally to avoid conversions to/from strings.)
a := 5 ; the variable "a" contains only a digit, but is not interpreted to be a number yet
b := a + 5 ; the variable "a" is required for a math operation (a + 5) so it is interpreted to be a number type variable because it's used in a math operation on this line
msgbox % "b is equal to: " . b . "`nThis is because the variable ""a"" was interpreted as a number, and added to 5 (b := a + 5) to evaluate to 10."
if a = 5 ; the variable "a" is required for a comparison (if a = 5) on this line, since the variable "a" contains only digits, it is interpreted as a number
{
	msgbox % "yes, the variable ""a"" is equal to 5!"
}
else
{
	msgbox % "no, the variable ""a"" is not equal to 5!"
}

; Here is an example where a variable does not contain only digits, so it's not interpreted as a number type variable when used in math operations or comparisons.
a := 5grams ; the variable "a" contains contains a digit, but also non-digits : it is not interpreted yet
b := a + 5 ; the variable "a" is required for a math operation (a + 5) but "a" does not contain only digits, so it's not interpreted as a number, the math operation fails silently and "b" evaluates to nothing (empty)
if a = 5 ; the variable "a" is required for a comparison (if a = 5) on this line, since the variable "a" contains only digits, it is interpreted as a number
{
	msgbox % "yes, the variable ""a"" is equal to 5!"
}
else
{
	msgbox % "no, the variable ""a"" is not equal to 5!"
}

;~ Variable scope and declarations: With the exception of local variables in functions, all variables are global; that is, their contents may be read or altered by any part of the script. 
a := "test"
gosub MyLabel


;~ To access variables created outside functions and use them inside functions they must be declared global variables outside of functions.
global a := "test"
msgbox % myFunction()
myFunction() {
	b := a . " worked"
	return b
}

;~ Alternatively, functions themselves can be declared global so that they can use variables created outside of functions.
a := "test"
msgbox % myFunction1()
myFunction1() {
	global ; this function is declared a global function by placing "global" on the first line inside of the function
	b := a . " worked"
	return b
}


;~ Variable names: Variable names are not case sensitive (for example, CurrentDate is the same as currentdate).
CurrentDate := "December 5th, 1805"
currentdate := "January 6th, 1906" ; The currentdate is the same as CurrentDate, so CurrentDate/currentdate both contain "January 6th, 1906" on the second line.
msgbox % "currentdate: " . currentdate . "`nCurrentDate: " . CurrentDate . "`ncURRENTdATE: " . cURRENTdATE

;~ Variable names may be up to 253 characters long and may consist of letters, numbers and the following punctuation: # _ @ $
abc := "test 1"
123 := "test 2"
#a# := "test 3"
_b_ := "test 4"
@c@ := "test 5"
$d$ := "test 6"
msgbox abc: %abc% `n123: %123% `n#a#: %#a#% `n_b_: %_b_% `n@c@: %@c@% `n$d$: %$d$%
return

MyLabel:
msgbox % a ; the variable "a" is found because variables created outside functions are accessible everywhere in the script except inside functions.
return