Important note: all examples follow aTbRef naming conventions.
Function arguments
A function's arguments are the terms—zero or more—that are defined within the parentheses following a function's name. Thus function fSomeTask(iNumber, iString){...
defines two discrete arguments: 'iNumber' and 'iString'. A function with no arguments function fReset(){...
is perfectly allowable, noting that parentheses must be included even if empty. This latter form, though valid, is less commonly used because in general the aim of the function's code is to manipulate one or more values passed to that function.
A function may, or may not, have one or more arguments. Multiple arguments are entered separated by commas (with optional whitespace after).
A value must be passed for every argument defined in the function, i.e. the action code calling the function must be written so as to supply a value for each argument defined by the function.
Functions with no input arguments must have parentheses
A user-defined function with no (zero) arguments is still required to be defined with empty trailing parentheses. For instance, this simple function that has no arguments and which simply returns a string value:
function fTestMessage(){return "Hello world."}
Similarly, those empty parentheses must be used when calling the function in action code:
$Text = fTestMessage();
WRONG $Text = fTestMessage;
Importantly this is a variation from general action code syntax where some action, especially dot-operators, where all arguments are optional and trailing parentheses may be omitted (e.g. .isort
vs .isort()
).
By comparison, the example function can not be called as fTestMessage
and must be called as fTestMessage()
despite there being no use of arguments. One reason is that the action code parser might mistake the 'bare' call as being just a literal string, due to support for legacy syntax where quoting strings was just an option.
Add an extra argument or make a new function?
Creation a use of a function can show that it might be useful if some conditional choice of process or return value were supported, e.g. returning a string in title case or all-lowercase. One way to do this is to add an extra boolean-type input. But, remember that all defined inputs must be used when calling a function. If not coding often for such functions it is easy to forget.
So, it is a matter of personal preference as to whether a better choice might be to make a copy of the original function, give it a new name, and alter the logic within. The reverse issue if you find something (a bug or possible improvement) on one of the functions it will be necessary to edit all of them. Also if versioning functions this way it can help future self if the function name indicated the altered behaviour from the original. So rather than copying fMakeString() as fMakeString2(), if the new version is to make an all-lowercase return value, fMakeStringLowercase() or fMakeString LC(), etc. might be more self-explanatory.
Naming arguments
Each input argument must have a discrete name. The argument's name must not be an attribute reference, e.g. "$MyString", or an attribute's literal name, e.g. "MyString". Within this restriction, the exact naming of the argument is the user's choice.
The argument name is essentially declaring/naming an internal variable for use (only) within the function, as explained further below: see 'Argument names as internal variables'.
In aTbRef documentation any function arguments in the parentheses use the same CamelCase convention as for attribute names but with an 'i' prefix. For example, this function definition code:
function fMakeTable(iSomeList){ ..code ...}
'iSomeList' will be a variable available within the scope of the function, i.e. in the function but not outside it. Calling the above function like so:
fMakeTable($CategoryList);
will result in iSomeList within the function holding a list containing the value of the calling note's CategoryList attribute.
An argument's name vs. the value name used in action code calling a function
It is important to understand that a function argument's defined name and the string defining the input for that argument as used in the code calling the function code are usually different. Thus, in the above example, the function is called supplying an argument value that is a reference to $CategoryList. But, inside the function for this execution of the function, the value of the first argument iSomeList will be tread from the $CategoryList attribute value in the calling note.
But, elsewhere other action code might call the same function but using code fMakeTable($MyList);
. For that execution, iSomeList within the function will hold the value of $MyList in the calling note. Or the calling code might pass a literal list, e.g. fMakeTable([ant;bee;cow]);
, with iSomeList now being the list passed into the function, i.e. as a list [ant;bee;cow]
.
Despite describing calling the function 'fMakeTable' with three differently described input, in every case, the supplied argument value is used internally via the argument's name, i.e. were 'iSomeList'.
So:
- Inside: inside the function the argument name is always are defined in the function code (e.g. $SomeList in the example).
- Outside: in code calling the function, a value is substituted where the argument is defined. These may be literal values (20, "Hello",
false
, etc.) or attribute references ($MyString).
Argument names as internal variables
When writing a function's code and including argument(s), an argument's name is implicitly defined as an internal variable. Using the example above, if a function's argument were defined as 'iSortList' then that exact name (i.e. the argument's user-defined name) can be used anywhere in the function's code as a variable that will have that value passed to the function via that argument input.
If the argument were instead named 'x' or 'abracadabra', the same applies, the argument name as defined in the function code is the name of the internal variable for that argument's input.
Therefore, the argument/variable name is set by the user by the action of writing the function code.
Note, that when copying another user's function code, as personal styles differ, a user may decide to use argument names more to their own style. If doing so it is important to change not only the argument name in the function's argument list but any occurrences of the argument name in the whole code of the function. In this simplistic example, function 'fGetListItem' takes a list as an argument and returns the value of the third item in that list (not second, as .at[] is zero-based):
function fGetListItem(iSomeList){
return iSomeList.at[2];
}
If having copied this code it was preferred to have an attribute 'L', then two substitutions are needed, one in the argument declaration and the second where it is used within the function:
function fGetListItem(L){
return L.at[2];
}
Externally, the call is still the same, e.g.:
$MyString = fGetListItem($SomeThings);
as it is only the internal name of the argument that has changed (from 'iSomeList' to 'L').
Argument data types
A function's arguments can be given an explicit data type, i.e. when used within the function the stated data type will be used
For example,
function fAppendFoo(iList:list){
return (iList+"foo");
}
Now 'iList' will be treated as a list without any type coercion needed. The argument's type is set in the function definition and in the above example the function would expect one argument and that it would be List-type date (attribute, literal list-string, etc. The range of data types, and how they are used is described in the article on variables, var().
Whilst it is not a requirement to give a type to any/all arguments, it is strongly recommended users do so—especially if new to function use. Why? Because previously, all inputs arrived as a string and if a definite type was needed inside a function, the input argument had to be passed to a type variable (or attribute) before use. For example,
function fAppendFoo(iList){
vr:list vList
return (vList+"foo");
}
By using explicit argument types, doing explicit type coercion within the function is avoided. So, less and clearer code.
Using argument input values within the function
Arguments are a received as a String data type (regardless of the source data in the calling code). Note that may change in future version, to allow enforced date-typing of arguments. But, at present assume type coercion occurs. That means most inputs will be assumed to be a String, List or Dictionary.
In the example above, calling the argument 'iSomeList' may indicate the term is a function argument and is intended to be List-type data, but it doesn't affect Tinderbox normal type coercion. A string with no semi-colons in it will be assumed to be a string. If semi-colons are found a list (essentially a List type) will be assumed.
To avoid incorrect parsing of inputs, it may be necessary to pass the input to a data-typed variable. Re-using the above example:
function fMakeTable(iSomeList:list){
var:list vList = iSomeList;
// ..tc.
}
Variable use is discussed further here.
It is equally possible to pass the argument to an attribute of the desired data type in order to assert data type for further use within the function.
Evaluation of input arguments
An argument my be an expression as well as an attribute value, variable or literal string/number. For instance:
$Result=fLastThreeWordsOf(fBestParagraphOf($Text));
Here, the actual value passed to function fLastThreeWordsOf()
is the evaluated result of fBestParagraphOf($Text)
, with $Text being the text of the calling note.
Simulating optional arguments
As stated above, every argument defined in the function's code, must receive an import or the function will not run correctly. To simulate an optional argument, pass a placeholder string ("none") and test that input within the function's code before using the argument, i.e. if "none" do nothing or else carry out some action using the argument's value. Here "none" is not a defined term. The value used in this context is up to the user. The point is that if using 'no value' value, the the input value must match whatever 'no value' string the user has defined in their function.
Next: Returning function values
See also—notes linking to here: