a Masterclass in Prototyping, the least-understood and most-valuable asset in Autohotkey v2

Helpful script writing tricks and HowTo's
sashaatx
Posts: 341
Joined: 27 May 2021, 08:27
Contact:

a Masterclass in Prototyping, the least-understood and most-valuable asset in Autohotkey v2

26 Dec 2023, 00:14

I am by far not the most educated, I have simply absorbed resources from the community and namely u/GroggyOtter. Most of my examples will use common methods from python and bridge those to autohotkey, such as Array.Contains() and Dictionary.Keys().

Using Prototyping in AutoHotKey: A Tool for Scripting In AutoHotKey (AHK) v2
In the realm of AutoHotKey (AHK) v2, developers are presented with a potent tool—prototyping—that transforms the scripting landscape by allowing dynamic assignment of methods to objects. Unlike traditional programming languages, Prototyping lets developers assign methods to objects dynamically, which is not typically seen in conventional programming languages. Prototyping in AHK allows developers to add their own custom methods during runtime and incorporate features from different programming languages into their AHK scripts.

Prototyping makes it easier to expand the functionality of AHK scripts. It works as a dynamic framework that helps with the addition of methods to objects in real-time. This becomes especially important when developers want to integrate functions similar to those in other programming languages, serving as a link for feature integration across languages.

In the developer's toolkit, prototyping is a flexible tool to improve script adaptability. It uses descriptors, configurations that describe how properties should be used, to combine methods in a straightforward way. This approach streamlines the development process and allows developers to merge desired features from different programming languages into their AHK scripts.

Pardon my eagerness, but prototyping in AutoHotKey is more than just an additional feature. It's a practical approach for developers interested in adding personalized features to their scripts. By using prototyping, scripts aren't limited by set methods, but can be built using a mix of functionalities from various languages. As developers start to use the prototyping feature, they'll find they can customize their scripts more effectively in AHK.

In summary, prototyping is a key feature in AHK scripting that enables scriptwriters to build adaptable and modular code structures. Its dynamic nature allows for changes to be made in real-time, which increases code reusability and simplifies complex operations. As scriptwriters use prototyping, they'll see an improvement in their scripting skills, resulting in more efficient and easier-to-maintain codebases.


Examples
Example 1: Groggy's Explainer - Adding the 'Contains()' method to Arrays. Akin to my_list.contains('string') => index pos in python

The script defines a custom method "Contains" for arrays, allowing users to check if a specific item is present. This method is added to the prototype of the Array class, making it accessible to all array instances. The array_contains function is responsible for the actual check, considering case sensitivity if specified. Examples with an array of fruits demonstrate how to use the custom method to determine if a particular item exists in the array. The comments have been simplified to provide clear explanations of each step.

Code: Select all

  /*
  You can add any property to any object
  This allows you to access the property at any time
  However, in this case, we want to add it to the object's prototype.  
  This gives all instances of the object access to the new property
  If you don't add it to the prototype, it won't be in the created objects, only the base object.  
  You'll want to create a descriptor. It's a special object that allows a property to be called
  (Spoiler alert, there are no TRUE "methods" in AHK.  
  They're ALL properties with callable descriptors.)  
  Descriptor object example: {Call:array_contains}
  The descriptor "describes" what actions a property should take
  */
  Array.Prototype.DefineProp("Contains", {Call:array_contains})

  ; When a descriptor is called, it ALWAYS sends a reference to the object as the first param.  
  ; It's known as the "this" variable when working inside an object/class/etc.  
  ; The search param is the expected item to find.  
  ; CaseSense is a bonus option added just to make the method more robust
  array_contains(arr, search, casesense:=0) {
      for index, value in arr {
          if !IsSet(value)
              continue
          else if (value == search)
              return index
          else if (value = search && !casesense)
              return index
      }
      return 0
  }

  ; Define an array
  arr := ['apple', 'banana', 'cherry']

  ; Now you can use the new "contains" method we just added  
  ; Remember, the array itself is passed implicitly and doesn't need to be included.  
  ; The "search" param is required and not providing one throws a parameter error  
  ; "CaseSense" is optional and defaults to false
  if arr.contains('Cherry')
      MsgBox('Found it!')
  else MsgBox('Not found.')

  ; Trying again, except this time using case sensitivity
  if arr.contains('Cherry', 1)
      MsgBox('Found it!')
  else MsgBox('Not found.')
Example 2: An empty example

Prototyping enhances script flexibility. Consider a scenario where you want to add a custom method to handle GUI elements.

Code: Select all

; Define a prototype method for GUI elements
GuiControl.Prototype.DefineProp("CustomAction", {Call: custom_action})

; Prototype method implementation
custom_action(control) {
    ; Your custom action logic here
}
Descriptors play a key role in prototyping. They define how properties are invoked. Let's see how descriptors work in a basic example.

Code: Select all

    ; Define a prototype method with a descriptor
    Object.Prototype.DefineProp("CustomMethod", {
        Call: custom_method
    })

    ; Prototype method implementation
    custom_method(CallingObject, param1, param2) {
        ; Your custom method logic here
    }
Example 3: Grabbing Keys and Values from a Map

Code: Select all

  ; This method is added to the prototype of the Map class to retrieve an array of keys.
  Map.Prototype.DefineProp("Keys", { Call: get_keys })
   ; M := Map("Key1", "Value1", "Key2", "Value2", "Key3", "Value3")
   ; M.Keys()  ; returns ["Key1", "Key2", "Key3"]
   ; now keys and values  can be immediately looped like this:
   ; for arr in myMap.Keys() {} 


  get_keys(mp) {
      mapKeys := []
      for k, v in mp {
          if !IsSet(k)
              continue
          else if k is string or k is number
              mapKeys.Push(k)
      }
      return mapKeys
  }

  ; This method is added to the prototype of the Map class to retrieve an array of string values.
  Map.Prototype.DefineProp("Values", { Call: get_values })

  get_values(mp) {
      mapValues := []
      for k, v in mp {
          if !IsSet(v)
              continue
          else
              mapValues.Push(v)
      }
      return mapValues
  }
Example 4&5: Simplifying Listview methods.

Example 4:

Code: Select all

/*
Class: get_row
Description: Represents a method to get the focused row of a ListView control.
Methods:
- Call(LV): Retrieves the focused row of the ListView control.
    Parameters:
        - LV: The ListView control.
    Returns:
        - An array containing the values of the focused row.

    Example usage:
    LV.GetRow()  ; LV is an instance of Gui.Listview
    Returns: ["Value1", "Value2", "Value3", ...] 
*/

Gui.Listview.Prototype.DefineProp("GetRow", { Call: get_row })
; define the prototype

get_row(LV)
{
        if not LV.Focused
            return 0
        FocusedRow := []
        Loop LV.GetCount("Column")
        {
            FocusedRow.Push(LV.GetText(LV.GetNext(), A_Index))
        }
        return FocusedRow
  } 
Example 5:

Code: Select all

/*
    Class: set_cell

    Description:
    This class provides a static method to set the value of a cell in a ListView control.

    Methods:
    - Call(LV, row, col, value): Sets the value of the specified cell in the ListView control.

    Parameters:
    - row (integer): The row index of the cell.
    - col (integer): The column index of the cell.
    - value (string): The value to set in the cell.

    Example usage:
    ```
    LV := Gui.Add("ListView")
    LV.SetCell(1, 2, "New Value")
    ```
*/
Gui.Listview.Prototype.DefineProp("SetCell", { Call: set_cell })
class set_cell
{
    static Call(LV, row, col, value)
    {
        LV.Modify(row, "Col" col, value)
    }
}
Get Set examples

Code: Select all

#Requires AutoHotkey v2
setterValue := 0
Obj := {}
; Helper Function for 'get'
getFunction(this) {
    return this._hiddenValue  ; Return the internally stored value
}
; Helper Function for 'set'
setFunction(this, value) {
    this._hiddenValue := value  ; Update the internally stored value
}
; Create an object and a hidden field to store the property value
myObject := { _hiddenValue: "" }
; Define a dynamic property with both getter and setter
myObject.DefineProp("DynamicProperty", {
    Get: getFunction,
    Set: setFunction
})
; Now you can get and set the value of DynamicProperty
myObject.DynamicProperty := "Hello, World"  ; Setter is called
MsgBox myObject.DynamicProperty  ; Getter is called and displays "Hello, World"
Last edited by sashaatx on 18 Jan 2024, 13:51, edited 10 times in total.
https://github.com/samfisherirl
? /Easy-Auto-GUI-for-AHK-v2 ? /Useful-AHK-v2-Libraries-and-Classes : /Pulovers-Macro-Creator-for-AHKv2 :
User avatar
andymbody
Posts: 924
Joined: 02 Jul 2017, 23:47

Re: a Masterclass in Prototyping, the least-understood and most-valuable asset in Autohotkey v2

26 Dec 2023, 12:42

Awesome! I will be digging into this! Thank you!! :thumbup:
niCode
Posts: 301
Joined: 17 Oct 2022, 22:09

Re: a Masterclass in Prototyping, the least-understood and most-valuable asset in Autohotkey v2

26 Dec 2023, 20:04

Thanks for the write-up. It'd be interesting to see what kinds of things we'll see if more people adopt using it.

I'm curious about a bit from this part though:

Code: Select all

Object.Prototype.DefineProp("CustomMethod", {
    Call: custom_method,
    Parameters: ["param1", "param2"]
})
Did you find the Parameters property somewhere in the docs or did someone mention it somewhere? Because I can't find any information about this. I know its use is obvious, but I'm still interested :)
vmech
Posts: 361
Joined: 25 Aug 2019, 13:03

Re: a Masterclass in Prototyping, the least-understood and most-valuable asset in Autohotkey v2

27 Dec 2023, 09:55

niCode wrote:
26 Dec 2023, 20:04
I'm curious about a bit from this part though:
It is just a prototype of the prototyping :lol:
Please post your script code inside [code] ... [/code] block. Thank you.
niCode
Posts: 301
Joined: 17 Oct 2022, 22:09

Re: a Masterclass in Prototyping, the least-understood and most-valuable asset in Autohotkey v2

27 Dec 2023, 16:40

vmech wrote:
27 Dec 2023, 09:55
niCode wrote:
26 Dec 2023, 20:04
I'm curious about a bit from this part though:
It is just a prototype of the prototyping :lol:
It just sounds like gibberish when you put it that way. But it does seem that I can change the word Parameters to something else and it'll still do the same, but Call is specific. This just leads to more questions, which is why I asked in the first place. I'm trying to understand how this works.
sashaatx
Posts: 341
Joined: 27 May 2021, 08:27
Contact:

Re: a Masterclass in Prototyping, the least-understood and most-valuable asset in Autohotkey v2

27 Dec 2023, 19:03

niCode wrote:
27 Dec 2023, 16:40
vmech wrote:
27 Dec 2023, 09:55
niCode wrote:
26 Dec 2023, 20:04
I'm curious about a bit from this part though:
It is just a prototype of the prototyping :lol:
It just sounds like gibberish when you put it that way. But it does seem that I can change the word Parameters to something else and it'll still do the same, but Call is specific. This just leads to more questions, which is why I asked in the first place. I'm trying to understand how this works.
true it appears this is an error, the potential options are:


Get: The function object to call when the property's value is retrieved.

Set: The function object to call when the property is assigned a value. Its second parameter is the value being assigned.

Call: The function object to call when the property is called.

Value: Any value to assign to the property.
https://github.com/samfisherirl
? /Easy-Auto-GUI-for-AHK-v2 ? /Useful-AHK-v2-Libraries-and-Classes : /Pulovers-Macro-Creator-for-AHKv2 :
niCode
Posts: 301
Joined: 17 Oct 2022, 22:09

Re: a Masterclass in Prototyping, the least-understood and most-valuable asset in Autohotkey v2

27 Dec 2023, 19:57

sashaatx wrote:
27 Dec 2023, 19:03
true it appears this is an error, the potential options are:


Get: The function object to call when the property's value is retrieved.

Set: The function object to call when the property is assigned a value. Its second parameter is the value being assigned.

Call: The function object to call when the property is called.

Value: Any value to assign to the property.
Yeah, I found that part pretty easily. The parameter part is still unclear. Does that mean the property Value is not literal here? Seems weird the docs wouldn't mention it if that's the case.
sashaatx
Posts: 341
Joined: 27 May 2021, 08:27
Contact:

Re: a Masterclass in Prototyping, the least-understood and most-valuable asset in Autohotkey v2

27 Dec 2023, 20:37

niCode wrote:
27 Dec 2023, 19:57
sashaatx wrote:
27 Dec 2023, 19:03
true it appears this is an error, the potential options are:


Get: The function object to call when the property's value is retrieved.

Set: The function object to call when the property is assigned a value. Its second parameter is the value being assigned.

Call: The function object to call when the property is called.

Value: Any value to assign to the property.
Yeah, I found that part pretty easily. The parameter part is still unclear. Does that mean the property Value is not literal here? Seems weird the docs wouldn't mention it if that's the case.
idk I find the section a bit scant, but in practice the params are set in the method/function not in the DefineProp
https://github.com/samfisherirl
? /Easy-Auto-GUI-for-AHK-v2 ? /Useful-AHK-v2-Libraries-and-Classes : /Pulovers-Macro-Creator-for-AHKv2 :
Cebolla
Posts: 4
Joined: 17 Feb 2024, 17:27

Re: a Masterclass in Prototyping, the least-understood and most-valuable asset in Autohotkey v2

21 Feb 2024, 15:57

Hello, thank you very much for the writeup. I was looking for something just like your "Get Set examples" and I'm about to try them out. I had one question though. At the top you initialized `setterValue := 0` but then that variable isn't referenced in the example. What is the setterValue supposed to symbolize?

Return to “Tutorials (v2)”

Who is online

Users browsing this forum: No registered users and 3 guests