I certainly have my gripes with many of the changes. However, I think most of the issues with moving to v2 stem from pre-conceived notions from v1, a sprinkle of pretty confusing error messages, and documentation that goes way too hard. I think all three of those are things that will get better over time.
The example from the original post is a prime example of bad documentation. That code focuses to much on what you can do, neglecting to show you what you probably actually want to do. I would rewrite it from
Code: Select all
main := Gui('+Resize')
main.OnEvent('Close', (*) => (wvc := wv := 0))
main.Show(Format('w{} h{}', A_ScreenWidth * 0.6, A_ScreenHeight * 0.6))
Code: Select all
main := Gui("Resize")
main.onEvent "Close", CloseRoutine
main.Show "w" A_ScreenWidth * 0.6 "h" A_ScreenHeight * 0.6
CloseRoutine(thisGui) {
global
; Erase global variables wvc and wv
wvc := unset
wv := unset
}
This conversation extends into the more general question of what happened to subroutines, and why?
Notably, functions are a type of subroutine, so to be clear I'm calling them "functions" and "labelled subroutines".
Label-based subroutines, mind the french, sucked in key ways.
Labelled subroutines were a primary reason that the auto-execute section existed, making it impossible to write code like
Code: Select all
x := "initial"
a::
msgbox %x%
return
y := "initial"
b::
msgbox %y%
return
Labelled subroutines depend on the existence and management of global variables, which pose unique challenges to people writing libraries, but also to people writing just their own every day code. When I'm working with code that GoSubs everywhere, it's frequently impossible to keep track of what state changes will result from the GoSub. It's possible to do something like
Code: Select all
; ... whatever code
; Populate alpha and beta to be processed by Routine
alpha := 1
beta := 2
GoSub Routine ; Saves results in gamma
Labelled subroutines are forced global. Functions give you the option, which you can very easily take.
Labelled subroutines don't nest properly, so if you want to make a new subroutine to handle, say, your GUI events inside of a subroutine or function that created the GUI, you end up tearing your hair out. This has been a huge problem in the past with labels like GuiClose, GuiSize, GuiDropFiles, etc. I acknowledge that you have to be a certain kind of person to run up against this with any frequency, but I am that kind of person.
The biggest point, from a language feature standpoint subroutines entirely duplicate the functionality of functions. The two can fight each other, but given that functions support all label features with some extra left over, functions will always win.
In v2, functions have new tricks that make their replacing labelled subroutines much easier to bear. Notably, they can read global variables now without having to mark them as global (though you must mark them as global to write to them).
You can call them by name as a command, meaning you can call them easier than a v1 labelled subroutine. In v1, you'd write GoSub subroutine, but in v2 you can now write just subroutine for any named function-based subroutine.
If you're build a GUI inside a function, you can now define the event handlers for that GUI also inside the function. And those functions defined inside functions can access and change the variables from the outside super duper easily, referencing just the ones for that instance of the GUI making it super duper easy to make your callbacks affect the variables you want. It's an absolute game changer.
Code: Select all
makeMyGui
makeMyGui() {
guiName := Gui("Resize")
guiName.SetFont "s16"
textControlName := guiName.AddText("c303030", "Width: 9999, Height: 9999")
guiName.onEvent "Size", ResizeMe
guiName.Show "w" 640 "h" 480
ResizeMe(guiName, minMax, width, height) {
; notice here, textName was grabbed automatically from the outside world
textControlName.Text := "Width: " width ", Height: " height
}
}
I don't know where I'm going with all this, except maybe to say that the documentation for v2 is misleading. A lot of the symbol soup can be thrown out, to reveal a more v1-ey language underneath. I do regret the removal of plain-text parameters, and the brief existence of variable de-referencing in strings with no practical replacement. But over all, it makes it better for power-users to create better tools for non-power-users and that's a good thing. It adds many stumbling blocks for people coming from v1, but I don't believe that's avoidable.
In the Discord we've been helping people completely new to v2 for many weeks now, and the biggest stumbling blocks are:
1. I installed v2 but I've copied v1 code from online into my script
2. (Frustratingly) I asked ChatGPT to help me with my code and it spat out absolute hot garbage which I pasted into my script
3. Just regular issues that people would have whether they were using v1 or v2, like not putting braces around indented if else blocks