6

In AutoHotkey, you can leave out arguments in the middle of a built-in function call as so:

MsgBox, 4,, Blah
MouseGetPos,,, MouseWin

You can also create functions with optional parameters à la C++:

Foobar(baz, blah="something")
{
  MsgBox baz=%baz%, blah=%blah%
}

However the docs say that when you create a function, you cannot have non-default parameters after a default parameter. Trying to do so will result in an interpreter error saying that the first non-default argument after a default argument requires a default.

Why? What’s wrong with calling it like so?

Foobar(baz, blah="something", blivet)
{
  MsgBox baz=%baz%, blah=%blah%, blivet=%blivet%
}

Foobar("cat",,"dog")

Is there a way to create functions with optional parameters in the middle?

Anthony Mastrean
  • 21,850
  • 21
  • 110
  • 188
Synetech
  • 9,643
  • 9
  • 64
  • 96

2 Answers2

7

When you omit a parameter in a built-in command (not function), what you're really doing is passing an empty string. There are differences between these two cases:

  • Defining a function with an optional parameter followed by mandatory parameters.
  • Calling a command with an omitted optional parameter followed by optional parameters which have not been omitted.

With both MsgBox and MouseGetPos, all parameters are optional.

AutoHotkey 1.1 allows the following with user-defined functions:

Foobar(1,, 3)
Foobar(baz, blah="something", blivet="")
{
    MsgBox baz=%baz%, blah=%blah%, blivet=%blivet%
}

This is only possible when the parameter's default value is known (i.e. not when calling a function dynamically).


Allowing the middle parameter to be omitted

If you do not want to change the order of the parameters or make two of the three optional, you can do a bit of "juggling":

Foobar("baz", "blivet")
Foobar("baz", "blah", "blivet")
Foobar(baz, p2, p3="omitted")
{
    blah := p3="omitted" ? "default" : p2   ; optional
    blivet := p3="omitted" ? p2 : p3        ; required
    MsgBox baz=%baz%, blah=%blah%, blivet=%blivet%
}

This way, the function always requires at least two parameters, and you're effectively allowed to omit the parameter in the middle when calling the function. However, you need to reserve a (string or numeric) value to indicate the parameter has been omitted. This can be avoided with AutoHotkey 1.1 by using a variadic function:

Foobar("baz", "blivet")
Foobar("baz", "blah", "blivet")
Foobar(baz, p2, p3*)
{
    blah := p3.MaxIndex() ? p2 : "default"   ; optional
    blivet := p3.MaxIndex() ? p3[1] : p2     ; required
    MsgBox baz=%baz%, blah=%blah%, blivet=%blivet%
}

Alternatively, the function can be declared as Foobar(baz, p*) and you can base your conditionals on p.MaxIndex() (the number of additional parameters), but in that case, only the first parameter is mandatory.

Lexikos
  • 987
  • 6
  • 16
2

Two options... (workarounds...)

1. Put all the parameters with default values on the right...

Foobar(baz, blivet, blah="something")
{
  MsgBox baz=%baz%, blah=%blah%, blivet=%blivet%
}

Foobar("cat","dog")

2. Define an "empty" default value...

Foobar(baz, blah="something", blivet="")
{
  MsgBox baz=%baz%, blah=%blah%, blivet=%blivet%
}

Foobar("cat",,"dog")

I can't say why this is like this, but for now, there is no other way... (unless you modify autohotkey :P )
I guess that built-in functions don't work the same way.

Joe DF
  • 5,438
  • 6
  • 41
  • 63
  • Unfortunately neither workaround is always possible. It’s really strange that they made such different syntax for built-in functions (which also use a command instead of parentheses). – Synetech Oct 03 '12 at 04:49
  • Not always possible?? Why? Why not just put the default parameter on the right? – Joe DF Oct 03 '12 at 15:57
  • The example does not contain a function, where there is a default parameter... -_- – Joe DF Oct 03 '12 at 20:48
  • *I considered adding a variable to the function so that depending on the value, the function either performs the normal function when triggered by the normal hotkeys, or builds a string or something when triggered from the special display hotkey.*  Like I said, it’s a *simplified* example. The actual function already has a default parameter; e.g., `SomeFunc(foobar, opt)`. If I end up having to add another parameter to be able to display the list, it would not be optional, and moving the meta-data parameter to be between the two data parameters is *physically* possible, but would be really bad. – Synetech Oct 04 '12 at 01:46
  • My current function is exactly like the example above (`Funcname(arg, optarg="")`). If I add another parameter to determine if the function is to run like normal or just for printing out the list, I cannot put it between the two data arguments. – Synetech Oct 05 '12 at 00:57
  • I considered making the meta-parameter a default as well; for example, `Funcname(arg, optarg="", mode=1`. But that wouldn’t work: `Funcname(foo)` = `Funcname(foo, "", 1)` but `Funcname(foo, 2)` <> `Funcname(foo, "", 2)`. I would *have to manually* add the `, ""` which defeats the purpose of the argument being default. Doing it the other way around (which is bad anyway because the meta-arg goes between the two data args) doesn’t work either: `Funcname(foo, 2)` = `Funcname(foo, 2, "")`, but `Funcname(foo, "bar")` <> `Funcname(foo, 1, "bar")`. Again, I would *have to manually* insert the `, 1`. – Synetech Oct 05 '12 at 01:04
  • Calling Funcname(foo,,"bar") should work With option 2... :s ?!? – Joe DF Oct 05 '12 at 10:02
  • Hmm, it looks like the second format does work. Of course the arguments after are optional instead of mandatory which means that there is the potential for bugs, but it is better than nothing. – Synetech Oct 08 '12 at 01:54