This chapter describes arguments to function calls in the
Curl® language.
In particular, it describes the following:
The information in this section applies to global procedures,
anonymous procedures, class procedures, methods, constructors, and
factories, which we will refer to collectively as functions, although
the examples shown are all of global procedures, for simplicity.
The concepts described in this chapter also apply to
text formats and text procedures. However, the arguments to text
formats and text procedures have a different syntax.
| Summary: | - Two categories: listed arguments and
rest arguments.
- Two formats: positional arguments and
keyword arguments.
|
Arguments allow you to pass information to functions.
There are two categories of arguments:
- Listed arguments, which are specified in
the function definition. Listed arguments correspond
to arguments as they are implemented in most other
programming languages.
- Rest arguments, which allow functions
to accept an unlimited number of unspecified arguments. A
rest argument is not individually named in the function
definition. Instead, three periods (...) at the
end of the list of arguments indicate that a function
accepts rest arguments.
These categories of arguments can include arguments passed
in either or both of the following formats:
- Positional arguments
If you include a positional argument in the argument
list, calls to the function must supply a value for each
positional argument. The number, data type, and order of
positional arguments in a function call must match those in
the function definition. The following code calls the
my-proc procedure, supplying an int positional
argument:
{my-proc 13} - Keyword arguments
Keyword arguments have default values. If a user does
not specify a value for a keyword argument, the function
uses the default value. To specify a keyword argument in
a function call, assign a value to the name of the
argument. The following code calls the my-proc
procedure, supplying an int value for the my-arg
keyword argument:
{my-proc my-arg=13}
| Summary: | - A caller must supply a value for each positional
argument.
- A caller must supply values for positional
arguments in the correct order.
|
A positional argument has the following syntax:
arg-name[:arg-type]
where:
- arg-name is the name of the argument. Use
a valid Curl language identifier when specifying arg-name.
You can use arg-name to access the value of the
argument from within the function.
- arg-type is the data type of the argument.
Use a valid data type when specifying arg-type.
Specifying the data type is optional. If you do not
specify arg-type, the argument assumes the
any data type.
Examples of positional argument definitions follow:
|| A procedure that takes one integer positional
|| argument (i)
{define-proc public {my-proc1 i:int}:void
|| Body of procedure
}
|| A procedure that takes one "any" positional
|| argument (a)
{define-proc public {my-proc2 a}:void
|| Body of procedure
}
|| A procedure that takes two positional arguments:
|| a bool (b) and a char (c)
{define-proc public {my-proc3 b:bool, c:char}:void
|| Body of procedure
}
The number, data type, and order of positional arguments in a
function call must match those of the function definition.
To supply a value for a positional argument, supply the value in
the call to the function. If you are supplying more than one
argument in a function call, use commas to separate the
arguments. For example, all of these are legal
procedure calls:
{my-proc1 13}
{my-proc2 13}
{my-proc2 'a'}
{my-proc2 "Hello"}
{my-proc2 true}
{my-proc3 true, 'a'}
| Summary: | - A caller need not supply a value for each keyword
argument.
- Each keyword argument definition includes a
default value.
- A caller can supply values for keyword arguments
in any order.
|
A keyword argument has the following syntax:
arg-name[:arg-type]=arg-value
where:
- arg-name is the name of the argument. Use
a valid Curl language identifier when specifying arg-name.
You can use arg-name to access the value of the
argument from within the function.
- arg-type is the data type of the argument.
Use a valid data type when specifying arg-type.
Specifying the data type is optional. If you do not
specify arg-type, the argument assumes the
any data type.
- arg-value is the default value of the
argument. arg-value can be any valid Curl language
expression. It is evaluated by the compiler in the scope of
the function being defined. The evaluation environment
is such that when arg-values are evaluated,
arg-names are initially bound to the appropriate
uninitialized-value-for-type..
Examples of keyword argument definitions follow:
|| A procedure that takes one integer keyword
|| argument (i)
{define-proc public {my-proc4 i:int=0}:void
|| Body of procedure
}
|| A procedure that takes two keyword arguments:
|| a bool (b) and a char (c)
{define-proc public {my-proc5 b:bool=true, c:char='a'}:void
|| Body of procedure
}
If the signature of a function has keyword arguments, you
need not supply values for those arguments when calling the
function. If you do not supply a value for a keyword
argument, the function uses the default value
(arg-value). To pass a value for a keyword argument,
assign the value to the name of the argument in the call to the
function. Because you are supplying the name of the argument
in the function call, you can supply keyword arguments in any
order. In the case of the my-proc5 procedure defined
above, this means each of the following is a valid procedure
call:
{my-proc5}
{my-proc5 b=true}
{my-proc5 c='q'}
{my-proc5 b=true, c='q'}
{my-proc5 c='q', b=true}
If a keyword argument is supplied multiple times, the last-supplied
instance of the keyword argument is used for the
argument binding. All other values are evaluated, type
checked, and discarded.
For example:
| Example:
Using Keyword Arguments |
 |
|| A procedure that returns the sum of two numbers.
{define-proc public {add-two-numbers number1:int=12, number2:int=13}:int
{return number1 + number2}}
|| Call the procedure, supplying the arguments.
{add-two-numbers}
{add-two-numbers number1=12}
{add-two-numbers number2=13}
{add-two-numbers number1=12, number2=13}
{add-two-numbers number2=13, number1=12}
{add-two-numbers number2=69, number1=12, number2=13}
| |
The following example illustrates the initial binding of keyword
arguments to
uninitialized-value-for-type. The example
attempts to set default values for the keyword arguments using
global variables that have the same names. This attempt fails,
because the global variable names are shadowed by the keyword
names, which are bound to the
uninitialized-value-for-type,
which is
0 for these integers.
| Example:
Show Initial Keyword Binding |
 |
{let number1:int = 12}
{let number2:int = 13}
|| A procedure that returns the sum of two numbers.
{define-proc public {add-two-numbers
number1:int = number1,
number2:int = number2}:int
{return number1 + number2}}
{add-two-numbers}
| |
| Summary: | - In the function definition, you can
specify positional and keyword arguments in
any order.
- In a function call, supply the positional
arguments in the same order as in the function
definition, but supply the keyword arguments
in any order.
|
To define a function with both positional and keyword
arguments, you can specify positional and keyword arguments
in any order. For example, in the following code, the
signature of the add-two-numbers procedure includes
one positional argument (number1) and one keyword
argument (number2):
{define-proc public {add-two-numbers number1:int, number2:int=13}:int
{return number1 + number2}
}
To call a function with both positional and keyword
arguments, you can supply the keyword arguments in any
position and in any order. However, you must supply the
positional arguments in the same order as in the function
definition. You can include keyword arguments among
the positional arguments. However, you must maintain the
relative order of positional arguments to one another.
The following example shows some of the different ways
that you can call the procedure defined above:
| Example:
Using Keyword Arguments and Positional Arguments |
 |
|| A procedure that returns the sum of two numbers.
{define-proc public {add-two-numbers number1:int, number2:int=13}:int
{return number1 + number2}
}
|| Call the procedure, supplying the arguments.
{add-two-numbers 12, number2=13}
{add-two-numbers number2=13, 12}
{add-two-numbers number2=69, 12, number2=13}
| |
| Summary: | - All arguments appear in the function
definition.
- Arguments can have the positional or keyword
format.
|
Listed arguments appear in the function definition. Listed
arguments can take the form of positional arguments or keyword
arguments. For example, the following procedure definition
has two listed arguments (arg1 and arg2). Both
of the listed arguments are positional arguments.
{define-proc {my-proc arg1:int, arg2:int}:bool
{return arg1 == arg2}
}
Also, the following procedure definition has two listed
arguments (arg1 and arg2). In this case, both
of the listed arguments are keyword arguments.
{define-proc {my-proc arg1:int=13, arg2:int=19}:bool
{return arg1 == arg2}
}
And finally, the following procedure definition has three
listed arguments (arg1, arg2, and arg3).
In this case, two of the listed arguments are positional
arguments and one is a keyword argument.
{define-proc {my-proc arg1:int, arg2:bool, arg3:int=19}:bool
{return (arg1 == arg3) and arg2}
}
| Summary: | - Three periods (...) at the end of the
list of arguments indicate that a function
accepts rest arguments.
- Arguments can have the positional or keyword
format.
- If a keyword argument is supplied multiple
times, the function uses the last-supplied
argument.
- You can optionally specify a data type for
the rest arguments. However, if you specify a
data type, you cannot have keyword arguments.
- Use a special form of the for loop to
access the arguments in the rest arguments
container.
|
Rest arguments allow functions to accept an unlimited number of
unnamed arguments. Rest arguments are not individually
named in the function definition. Instead, three periods
(...) at the end of the list of arguments in the
function definition indicate that a function accepts rest
arguments.
If (...) appears in the definition of the function,
any number of rest arguments can be supplied when calling
the function. If you want, you can supply no arguments.
Like listed arguments, rest arguments can take the form of
positional arguments or keyword arguments.
Rest arguments are actually stored in a rest arguments
container, with ... representing the container. All
rest arguments are stored in the container in the order in
which they are encountered. You can then iterate over
the container to access the arguments. Duplicate keyword
arguments are not merged in the rest arguments
container. This means that if a keyword argument is
supplied multiple times, the rest argument mechanism
stores all occurrences.
You can optionally specify the data type for rest
arguments. If you specify the data type, then the rest
arguments cannot include keyword arguments and each
argument must have the specified data type. For example,
the following code defines a set of rest arguments, each
of which has the String data type:
To specify rest arguments, include three periods (...) at
the end of the list of arguments. For example:
|| A procedure that takes rest arguments.
{define-proc public {my-proc6 ...}:void
|| Body of procedure
}
|| A procedure that takes two keyword arguments:
|| a bool (b) and a char (c) and rest arguments.
{define-proc public {my-proc7 b:bool=true, c:char='a', ...}:void
|| Body of procedure
}
It is also possible to specify a data-type for the rest arguments.
This can be very useful. For example:
|| A procedure that can take any number of int arguments
{define-proc public {my-int-proc ...:int}:void
|| Body of procedure
}
To access the arguments in a rest arguments container, use a
special form of the
for loop. The syntax of
this form of the
for loop follows:
{for (val-identifier, key-identifier) [key loop-counter] in ... do
statements
}
where:
- val-identifier is a variable that holds the
value of the argument for each iteration through the
rest arguments container. The data type of
val-identifier defaults to any or to
whatever data type was specified for the rest arguments,
if any.
- key-identifier is a variable that holds the
keyword of the argument, if present, for each iteration
through the rest arguments container. key-identifier
has the #String data type. If the current
element is a positional argument, key-identifier
is null.
- loop-counter is an int that holds the
current value of the loop counter.
If the rest arguments supplied by the caller do not include
keyword arguments, use the following syntax:
{for val-identifier [key loop-counter] in ... do
statements
}
When the runtime encounters the for loop, it iterates through
the rest arguments container, executing statements for
each argument. For example:
| Example:
Working with Rest Arguments |
 |
|| A procedure that takes rest arguments and returns a StringBuf.
{define-proc {my-proc ...}:StringBuf
|| A variable to hold the return value of the procedure.
let result:StringBuf = {StringBuf}
|| For each value in the rest arguments container, concatenate
|| the value to the string and append a space to the end
|| of the string.
|| Note that this loop will generate a runtime error if the
|| rest arguments container has a keyword argument (or, in
|| fact, any argument that is not a StringInterface, which is
|| the base class for strings in the Curl language).
{for v in ... do
{result.concat v}
{result.append ' '}
}
|| Return the string
{return result}
}
{value
|| Some strings.
let s1:String = "Here"
let s2:String = "comes"
let s3:String = "Curl!"
|| Call the procedure, supplying the strings as rest arguments.
{my-proc s1, s2, s3}
}
| |
Remember that you can pass a rest arguments container as an
argument in another function call. For example:
| Example:
Passing a Rest Argument Container as an Argument |
 |
|| A procedure that takes rest arguments and returns a VBox.
{define-proc {my-vbox ...}:VBox
|| Return a call to VBox with the rest arguments container
|| as the first argument. Because the "background"
|| and "spacing" arguments appear after the rest
|| arguments container, these settings will always take
|| effect (even if the same keyword argument appears
|| in the rest arguments container). You can use this
|| technique to ensure that default settings are applied,
|| even if other values are specified as rest arguments.
{return {VBox ..., background="pink", spacing=5pt}}
}
{value
|| Call the procedure, supplying the following rest arguments:
|| 1) a keyword argument indicating the background color of
|| the VBox
|| 2) a keyword argument indicating the alignment in the VBox
|| 3) a String to place in the VBox
|| 4) a Button to place in the VBox
|| 5) a String to place in the VBox
|| 6) a keyword argument indicating the margin of the VBox
{my-vbox
background="beige",
halign="center",
"Hello World",
{CommandButton label="Click Me!"},
"Goodbye",
margin=5pt
}
}
| |
Since rest arguments are not reflected in the definition
of a function, you should explicitly document the intended
contents of rest arguments. This will help to ensure that
those calling the function supply the correct rest arguments.
When documenting rest arguments, you should specify the
following:
- The data type and order of positional arguments.
- Whether a positional argument is mandatory or optional.
- The keyword, data type, and default value of keyword
arguments.
If you call a function that takes rest arguments, check
the documentation for the function to determine which
arguments you should supply. According to the syntax
of the Curl language, supplying rest arguments
is optional.
| Summary: | - If you are passing a rest arguments container
as an argument to a function call, make sure
that the function being called takes rest
arguments.
- If you are calling a function that takes
both positional arguments and rest arguments,
try to supply the number of positional
arguments that the function is expecting.
- Avoid the use of keyword arguments in
rest arguments containers that you pass as
arguments in function calls.
|
Working with arguments to function calls requires system
resources at compile time and at run time. In most cases,
these resource requirements are not significant. However,
you might want to take care to avoid certain uses of rest
arguments that might result in excessive demands on the
system during execution of a program.
If you are passing rest arguments containers as arguments to
function calls, make sure that the functions being called
take rest arguments. Also, try to make sure that the last
argument in the function call is the rest arguments container
and that the last argument in the argument list of the
function that you are calling is rest arguments.
Also, if you are calling a function that takes both positional
arguments and rest arguments, try to supply the number of
positional arguments that the function is expecting. If you do
this, it is not necessary for a new rest arguments container to be
created. For example, in the following code the call to foo in bar results in more efficient operation than the
call to foo in baz:
|| A procedure that takes one positional argument and
|| rest arguments.
{define-proc {foo x:int, ...}:void
|| Body of procedure.
}
|| Efficient use of rest arguments: the call to "foo"
|| has one positional argument and the rest arguments
|| container.
{define-proc {bar ...}:void
{foo 37, ...}
}
|| Inefficient use of rest arguments: the call to "foo"
|| has a positional argument, another positional
|| argument, and the rest arguments container.
{define-proc {baz ...}:void
{foo 37, 94, ...}
}
Try to avoid the use of keyword arguments in rest argument
containers that you pass as arguments in function calls. They
result in very inefficient operation.
| Summary: | - The Curl language uses the Arguments class to handle
arguments to function calls.
- Like a rest arguments container, an Arguments
object is a container that holds the arguments.
|
The Curl language uses the
Arguments class to treat argument
containers as first-class values. You can use the
Arguments class to create
Arguments objects.
An
Arguments object is actually a container that
holds the arguments (in much the same way as the rest
arguments container is a container that holds arguments).
For example, the following code defines an
Arguments
object and initializes it with a number of positional and
keyword arguments:
let args:Arguments = {Arguments background = "beige",
color = "blue",
"Here...",
"comes..."}
You can use the fields and methods of the
Arguments
class to work with the arguments in the container. For more
information, see the description of
Arguments in
the API Reference. To pass the arguments
in an
Arguments container as arguments to a function
call, you can use the
splice expression, which is
described in the next section of this chapter.
As with rest argument containers, you can use a special form
of the
for loop to access the arguments in an
Arguments object. The syntax of this special form
of the
for loop follows:
{for (val-identifier, key-identifier) [key loop-counter] in arg-object do
statements
}
where:
- val-identifier is a variable that holds the
value of the argument for each iteration through the
Arguments object. The data type of
val-identifier will be inferred.
- key-identifier is a variable that holds the
keyword of the argument, if present, for each iteration
through the Arguments object.
key-identifier has the String data
type. If the current element is a positional argument,
key-identifier is null.
- loop-counter is an int that holds the
current value of the loop counter.
- arg-object is the Arguments object.
If an Arguments object might contain keyword arguments,
make sure to include the key key-identifier
syntax. If you do not, a runtime error will be thrown.
When the runtime encounters the for loop, it iterates through
the elements of the Arguments object in sequential order,
executing statements for each argument.
| Summary: | - splice takes a container and returns the
elements of the container as a list of arguments.
- You can use splice with various containers
including arrays, strings, queues, sets, hash tables,
Arguments objects, and rest argument
containers.
- Because the compiler simply replaces the
splice expression with the elements of the
container in the form of a list of arguments, you can
treat a splice expression as a list of
arguments.
|
The Curl language has a special expression called
splice that
takes a container and inserts its elements into a list of
arguments. This allows you to easily supply the elements
of a container as arguments to a function call. For example,
you can use the
splice expression to include all the
elements of an array as arguments to a function call. You
can also use the
splice expression to pass the contents
of containers like an
Arguments object to a function.
You can use
splice with any container that a
for
loop can iterate over. Such containers include arrays, strings,
queues, sets, hash tables,
Arguments objects, and rest
argument containers. Because the compiler simply replaces
the
splice expression with the elements of the container
in the form of a list of arguments, you can treat a
splice
expression as a list of arguments.
This is a very powerful feature that is not a part of other
programming languages, such as C, C++, and Java™. When you
compile source code that includes a splice expression,
the compiler replaces the splice expression with
the elements of the container in the form of a list of
arguments. However, note that you can use the splice
expression only in the context of a list of parameters. You
cannot use it as a general-purpose way to access the elements
of a container.
The splice expression has the following syntax:
{splice container-name}
where
container-name is the name of the container.
You can use
splice with most containers in the Curl
language, including arrays, strings, queues, sets,
hash tables,
Arguments objects, and rest argument
containers. For example, to call
splice for an
Array
called
my-array, use the following syntax:
A splice expression can appear only in the context of a
list of arguments to a function call. So the
example above, in its proper context, might look something like:
{my-proc {splice my-array}}
Because the compiler simply replaces the splice
expression with the elements of the container in the form of a
list of arguments, you can treat a splice expression
as a list of arguments. In other words, you can include a
splice expression at any position in the list of
arguments. For example, all of the following uses of the
splice expression are valid:
{my-proc {splice my-array}}
{my-proc {splice my-array}, arg-n}
{my-proc arg-1, arg-2, {splice my-array}}
{my-proc arg-1, arg-2, {splice my-array}, arg-n}
You can use the
splice expression with the two most
common containers for arguments to function calls: a rest
arguments container (
...) and an
Arguments
object. When you use the
splice expression with one
of these argument containers, it returns both the positional
and keyword arguments, preserving the order of the arguments.
However, using
splice with a rest arguments container
is redundant; the rest arguments container returns the
arguments in the same format. The following example shows
the use of
splice with an
Arguments object that
contains both positional and keyword arguments:
| Example:
Using splice with an Arguments Object |
 |
{value
|| Define an Arguments container and initialize it with
|| a number of positional and keyword arguments.
let args:Arguments = {Arguments background = "beige",
color = "blue",
"Here...",
"comes..."}
|| Define a VBox and initialize it with the return value
|| from a call to the spaced-vbox procedure.
|| A "splice" expression includes the arguments from the
|| Arguments object initialized above.
let vb:VBox = {spaced-vbox
"Hello world!",
{splice args},
"Curl!"}
|| Display the VBox
vb
}
| |
When used with containers that are not designed specifically to
hold arguments, the splice expression returns the
elements as positional arguments. This is the case, even if the
container supports the keyword syntax and includes keywords. If
the splice expression encounters a keyword in a container that
is not designed specifically to hold arguments, it ignores the
keyword.
The following example shows the use of splice with
an array:
| Example:
Using splice with an Array |
 |
{value
|| Define an array of strings and initialize it with
|| three strings.
let some-strings:StringArray =
{new StringArray, "Here...", "comes...", "Curl!"}
|| Define a VBox and initialize it with the return value
|| from a call to the spaced-vbox procedure.
|| A "splice" expression includes the elements of the
|| array initialized above as arguments in the procedure call.
let vb:VBox = {spaced-vbox
"Hello world!",
{splice some-strings}}
|| Display the VBox.
vb
}
| |
To further illustrate the use of the
splice expression,
consider the problem of concatenating the contents of an array
of
Strings. You can create a
StringBuf to
hold the intermediate contents of the string. Then, you can
iterate through the elements of the array, concatenating each
String to the
StringBuf. And finally, you can
convert the
StringBuf to a
String. However, by
using the
splice expression, you can simply supply the
elements of the array as arguments to a call to
String.
For example:
| Example:
Using splice with Strings |
 |
{value
|| Define an array of strings and initialize it with
|| three strings.
let some-strings:StringArray =
{new StringArray, "Here...", "comes...", "Curl!"}
|| Define a String and initialize it with the return value
|| from a call to splice. The "splice" expression includes
|| the elements of the array defined above.
let output-string:String = {String {splice some-strings}}
|| Display the String.
output-string
}
| |
Copyright © 1998-2019 SCSK Corporation.
All rights reserved.
Curl, the Curl logo, Surge, and the Surge logo are trademarks of SCSK Corporation.
that are registered in the United States. Surge
Lab, the Surge Lab logo, and the Surge Lab Visual Layout Editor (VLE)
logo are trademarks of SCSK Corporation.