AutoHotkey Tip of the Week: Use the Variadic Function Parameter for an Unknown Number of Values in Hotstring Menus

What To Do When You Don’t Know How Many Values You Will Use? For Hotstring Menus, the Variadic Function Parameter Allows a Variable Number of Arguments or Direct Array Input

Variadic Function: One which accepts a variable number of arguments.

MenuEmojiTagsLight Bulb!In the blog, “AutoHotkey Tip of the Week: Hotstring Menu Techniques for Inserting Symbols and Emojis“, I discussed switching from the deprecated StringSplit command to  StrSplit() function before posting the scriptAfter posting my new HotstringMenu.ahk script on the AutoHotkey forum, I received the following comment from the user Delta Pythagorean. I have mixed feelings about the recommended changes:

You can simplify this down by making the parameter variadic and letting the user chose which label to set the menu to work off of.

:x:brb::HotStringMenu("MenuLabel","Hello",,"Goodbye","See you later!")

MenuLabel:
  MsgBox, % "You said: " A_ThisMenuItem
Return

HotstringMenu(Handle, TextList*) {
  For Each, Item in TextList
    Menu, MyMenu, Add, % Item, % (Item != "") ? Handle : ""
  Menu, MyMenu, Show
  Menu, MyMenu, DeleteAll
}

I like the overall concept. This change to the HotstringMenu() function expands its capabilities by adding a selectable subroutine Label name and uses a variadic parameter which allows the functions to accept an unknown number of values. AutoHotkey Library Membership!A variadic parameter offers a number of advantages:

  1. Variadic parameters can accept an undefined number of input arguments.
  2. The variadic input parameter automatically loads into a variable array by the same name.
  3. Since it loads into an array, no need to parse the variadic parameter using the StrSplit() function.
  4. In variadic inputs, you can mix comma delimited text (“text1”, “text2”, etc.) with variables (“text1”, var1, “text2”, var2, etc.)
  5. The variadic parameter accepts direct input of an object (including associative arrays) using a Variadic Function Call.
  6. The For-loop works for processing the array while skipping empty array values.

On the downside, you can only designate the last parameter of a function as variadic—limiting it to a single-use. On the other hand, the parameter parsing technique found in my original script can appear any number of times anywhere in the function parameters.

Designating the Target Subroutine

The primary differences between the recommended function calling format and that of my original script involve the addition of a parameter for the subroutine name (Label) and listing each menu item as if a separate parameter rather than a single all-encompassing value list. If you need to use multiple action subroutines, then designating the appropriate subroutine makes total sense. As for using the variadic parameter, both my original approach and the variadic function do virtually the same thing.

(I plan to discuss variable target subroutines in a separate blog.)

Beginning AutoHotkey Hotstrings 200px

I first introduced Hotstring menus in Chapters Eight and Nine of my book Beginning AutoHotkey Hotstrings. I started off with the StringSplit command which uses pseudo-arrays, then ultimately switched to the StrSplit() function which creates a simple array. Delta Pythagorean has prompted me to take a closer look at the utility of the variadic parameter.

The Variadic Function Parameter

Use the variadic parameter when you don’t know how many values or arguments you will need in the calling function. To create a variadic function add an asterisk to the last parameter:

HotstringMenu(Handle, TextList*)

This turns the parameter TextList into an array of values. That means you can add any number of extra parameters in the calling function with each loading into the TextList[] array.

Note: Only the last parameter in the function can act as a variadic.

The format of my original function call—which uses a single input value—only required a list of menu items separated by commas:

:x:brb::HotStringMenu("Hello,Goodbye,,See you later!")

The function then uses the StrSplit() function to parse the parameter into its component parts.

The variadic function call uses the following multiple parameter input format:

:x:brb::HotStringMenu("MenuLabel","Hello",,"Goodbye","See you later!")

The variadic format eliminates the need for the StrSplit() function to parse the input into an array. Plus, since it no longer acts as a delimiter, a comma can appear anywhere in an input value without causing a parsing problem. Both approaches create arrays—required for For Key, Value in Expression command support.

The Variadic Function Accepts Array Input

A variadic parameter can directly accept an array from a variadic function call by placing a corresponding asterisk * after the array name:

TestArray := {KeyA: "ValueA", KeyB: "ValueB", KeyZ: "ValueZ"}
x:brb::HotStringMenu("MenuLabel",TestArray*)

You can also place an array definition directly into the variadic parameter by adding a comparable asterisk:

x:brb::HotStringMenu("MenuLabel",{KeyA: "ValueA", KeyB: "ValueB"
                                , KeyZ: "ValueZ"}*)

OctoberSpecialEnd

In this case, the curly brackets create an associative array. (You can use both the key and value in the menu-building code.)

This array name or definition passing technique only works with functions including a previously designated variadic parameter.

For Key, Value in Expression Loop

In Chapter 12.1.6, “The AutoHotkey ‘For Key [, Value] in Expression’ Loop for Associative Arrays” of my book Jack’s Motley Assortment of AutoHotkey Tips, I discuss the uses and limitations of the array specific For Key, Value in Expression command loop. As long as the values appear in an array object (simple or associative array), you can use the For Key, Value in Expression command.

In my original script, I used the standard Loop command:

Loop % MenuItems.MaxIndex()
  Menu, MyMenu, add, % MenuItems[A_Index], HotstringMenuAction

The For Key, Value in Expression command functionally operates in the same manner:

For Each, Item in TextList
  Menu, MyMenu, Add, % Item, % (Item != "") ? Handle : ""

The last part of the Menu command in the latter example above includes a ternary operator (% (Item != “”) ? Handle : “”) to skip blank or null values when adding a subroutine Label to a menu. However, since the For-Loop automatically skip empty array items, the command does not require the extra code:

For Each, Item in TextList
  Menu, MyMenu, Add, % Item, % Handle

I could not have used the For Key, Value in Expression command with my first version of the HotstringMenu.ahk script since it used pseudo-arrays. The For Key, Value in Expression command only works with true arrays.

I haven’t yet made these recommended changes to the HotstringMenu.ahk script. I’m considering the implications of variable action subroutines.

Click the Follow button at the top of the sidebar on the right of this page for e-mail notification of new blogs. (If you’re reading this on a tablet or your phone, then you must scroll all the way to the end of the blog—pass any comments—to find the Follow button.)

jack

This post was proofread by Grammarly
(Any other mistakes are all mine.)

(Full disclosure: If you sign up for a free Grammarly account, I get 20¢. I use the spelling/grammar checking service all the time, but, then again, I write a lot more than most people. I recommend Grammarly because it works and it’s free.)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s