Default argument values....

Paragon

Member
Would it be difficult to allow function declarations to have default argument values.
Such as
void print_default(string s = "This is the default string")
{
print (s);
}


So that it could be called:
print_default();
print_default("I like cheese");

which would produce the output
This is the default string
I like cheese

Or would it be possible to allow main() to be overloaded?
 

Paragon

Member
Mainly I would use it for scripts that took no input but allowed switches. For instance:

Lets say that I wanted a script that would drink the best drink it could find, by default it would drink only drinks that you currently had in your inventory and not buy any items or drinks from NPCs or the mall. But it allowed a -buyNPC or -buyMall switch so that you could call it in the following ways:
bestDrink
bestDrink -buyNPC
bestDrink -buyNPC -buyMall
bestDrink -e4

where
bestDrink would drink the best drink you had in your inventory reguardless of how drunk it made you.
bestDrink -buyNPC would drink the best drink you had in your inventory, could buy from an NPC or required items that could be bought from an NPC
bestDrink -buyMall would drink the best drink in your inventory or if you didn't have the drink on the top of the bestDrinks list would buy it from the mall.
bestDrink -e4 would only drink the best drink from your inventory that gave a drunkeness of 4
bestDrink -adv would drink the best drink for adventures
bestDrink -mox would drink the best drink for moxie substat

etc. etc. But since it doesn't REQUIRE input it should be able to be run without a prompt being popped up, and you shouldn't have to use bestDrink -noArgs

Another example would be getElementalWeakness
since each elemental monster has two elemental weaknessess it would default to grabbing the weakness closest to cold but calling getElementalWeakness second would get the second elemental weakness.


Granted the second example can be worked around by using overloaded functions, but it is rather cumbersome. The first example I think is one of the better examples of how it would work and why it would be useful and how there is no current equivilent functionality. For example there are many scripts now where the behaviour can be changed by altering some of the global variables in the scripts code. But in order to do this you need to open the code, find the variable you want to change, figure out what valid data you have to change the value to, save the script (hoping you didn't accedently break anything) then run the script. Then if you want to run the script the normal way you have to go undo all those changes. With this method it would be very easy for script writes to allow users to modifiy the functionality right from the gCLI.
 

macman104

Member
Well, I thought I'd try out the following code
Code:
void main(string args)
{
	string [int] argsList = args.split_string("-");
	foreach arg in argsList
	{
		print(arg);
	}
}
But mafia still prompted if I left out the string argument (I hoped it would just assume an empty string)...*shrug*
 

Paragon

Member
Right, that is pretty much exactly how I do it with maximize.ash right now. But there is no way to do it without the prompt. Which is why I was requesting either a) a way to use default argument values so

void main(string args=" ")
{
<use the args to set flags and such>
<blassy blassy>
}

or b) overload main so

void main()
{
<code stuff>
}
void main(string args)
{
<set flags>
main();
}

Either method would work, but neither is currently available in ash.
 

holatuwol

Developer
I see.

The most straightforward, but still non-trivial, implementation (defining all possible method permutations) wouldn't apply to main() because of how ASH looks for it. If all you actually want is for main() itself work in this way, I can remove the feature which prompts for missing variables and just initialize them all to default values.
 

Veracity

Developer
Staff member
[quote author=holatuwol link=topic=1573.msg7363#msg7363 date=1204059818]
If all you actually want is for main() itself work in this way, I can remove the feature which prompts for missing variables and just initialize them all to default values.[/quote]
But...I LIKE being prompted for missing variables.

The only script I ever use is a pipe farming script which has the following signature for main() in it:

Code:
void main( int cycles, location place )

I start up the script by saying "farm-pipes.ash", KoLmafia asks me how many pipes I want to get and where I want to adventure when I'm not in the Wormwood, and off it goes.

I'd be sad if I have to specify all the arguments on the command line, being especially careful about specifying the location, rather than being able to simply select the location from the list of all locations...
 

Paragon

Member
Would it be easy to add a settings option which would allow you to set it as either true or false where setting it as true made the prompt appear and setting it as false allowed scripts to run without the prompt?

Or, I don't know much about how ash works this might be alot harder then I imagine... but possibly having a script which uses
main() as it is for the main function would act as it does now... poping up a prompt, and if you use mainnp() it would not popup the prompt. mainna meaning main no prompt or some such. Like I said this may be the worst idea you have ever heard.
 

Veracity

Developer
Staff member
The most versatile system I've seen for this kind of thing is Common Lisp's. Any function can have:

- 0 or more required arguments
- 0 or more optional arguments - with (optional) user-specified defaults
- 0 or more optional "keyword" arguments -
- 0 or 1 "rest" argument which gets a list of all the extra arguments the user passes in that don't get bound to another argument.

You would specify it like this:

Code:
(defun func ( a b &optional c (d 12) &key e (f "abc") &rest g)
...even omiting additional syntax which let the function figure out whether the user specified an optional parameter or whether it got its default value.

ASH has:

- 0 or more required arguments on main()
- the last of which acts as a "rest" argument, if the user passes in extra stuff.

I don't think I have time to do the language design to decide on pleasant syntax to improve on that - or to implement it, once such a syntax is defined. I imagine that the original suggestion of including " = default value " is not too bad, but it seems like it will be tricky to implement. You can already overload functions. So, if I define the following:

Code:
int func( int a, int b = 2)
...
int func( int a )
then, which function do we call if you then code:

Code:
func( 10 );
Do we call the first one, with second parameter bound to the default value of 2, or do we call the second one?

Given that, I think it'd be best to just do something special with main() - either allow special syntax for arguments there, or allow it to be overloaded. I think the latter would be confusing.

Specifying "main", "mainnp", and "mainna" as variant versions of main to call depending on what command line arguments the user typed seems like a kludge to me. Sorry.
 

holatuwol

Developer
Okay, Veracity has spoken, so prompting is staying.

I'm hesitant to implement the alternative because it'd break a lot of scripts, but ... a Javascript-style way to do it would be to put it all in a string[int] called 'args' accessible to every function, and then the user would just declare a zero-arg function.
 

Veracity

Developer
Staff member
I was thinking something similar earlier, when I was composing my response and thinking about the current implementation of the "rest" argument - the last argument which collects all the arguments into a string. Somebody pointed out a bug in this, a week or two ago, when they pointed out that a consult script (which takes three string arguments) generated a stack trace if you declared it to have zero arguments, because KoLmafia wanted to concatenate the extra arguments in a string and put it in the last - out of zero - arguments. Well, that's not what they reported, but that's what I discovered when I investigated and fixed the stack trace.

To recap my thoughts:

- We have function overloading. Therefore, I oppose general optional arguments for functions because defining how overloaded functions and optional arguments work is likely to be complicated, confusing, and error-prone.

- We have a special "main" function, but you can't overload that. I approve of that, since I think overloading "main" will lead to difficult to understand code, both for the user and for the coder. I think there should be one "main" function which looks at its argument and decodes them and dispatches appropriately.

- We already have special processing for the arguments for "main". If you specify a version with N arguments, KoLmafia prompts you for any arguments you didn't specify on the command line. I like that and want to keep that. If you specify extra arguments on the command line, KoLmafia concatenates them into a string and passes that as the last argument - it treats it as a "rest" argument. I like the ability to do that, but find the implementation less than elegant.

I conclude that having special processing for the arguments to "main" is acceptable - but coming up with a "clean" syntax to specify defaults and/or a "rest" argument is a fair amount of work - and implementing it is a fair amount more work. Either holatuwol or I is capable of it - I have years of specific experience in language implementation, and holatuwol is a generally smart guy - but adding syntax to ASH is non-trivial.

I quite like the array of string args. I think that's a cleaner alternative to the current way of doing "rest" args by concatenating extra arguments into a string. So:

If the user specified x number of arguments to main(), pull them off the command line, as now, and prompt for any missing.

When main() is called, arguments are bound to variables - as now - but also all arguments are available in a string[int] array. No more concatenating extra arguments into a final "rest" argument. Instead, main() can manipulate the values in args[] as needed to figure out the arguments.

I like that. No extra syntax. Instead, some not-too-difficult argument processing when main() is called. And the only things it would break would be scripts that expect extra arguments to be concatenated into the final "string" argument. There may not even be any such scripts.
 

Paragon

Member
Actually I guess I may have thought of a work around. Basicly create an alias that calls the script with an arbitrary character or string plus the input argument of the alias.

Say the script is called myScript in which void main(string args)

would it be possible to create an alias which would be something along the lines of
alias myAlias call myScript.ash -%%

So that when you use it with no arg it would do: call myScript.ash -
but if you used an arg (-myswitch) it would do: call myScript.ash --myswitch

I am not sure if this is how aliases work in kolmafia... everytime I have attempted to create an alias it has told me that it is an invalid aliasing. Actually I am not sure if aliasing is working correctly at the moment because even when I copied one of the alias on the forum verbatum it gave me that invalid aliasing error.
 

zarqon

Well-known member
A rather simple solution would be to have mafia automatically supply default values for all params in main() as per hola's initial response, but add some kind of prompt() function to ASH, akin to get_user_input() but valid for all basic data types. Authors writing scripts requiring user entry could use prompt() at the top of main(), and authors who want optional values could make them arguments in main(). Existing scripts would be very easy to convert (although probably quite confusing for the users unaware of this update). This also easily allows for combinations of optional and prompted values, without overloading main(). Just a thought.

NOTE: If mafia were to go this way, I'd warn you not to include a cancel button on the dialog box.
 
Top