This section describes variables in the Curl® language.
In particular, this section describes the following:
| Summary: | - Variables can be declared using let or def.
- Uninitialized variables are implicitly assigned a default value.
- If you do not declare the type of a variable, it is implicitly
inferred from the initial value when using the def
syntax and otherwise is assumed to take the any
type.
- Code with variables that have the
any data type may take longer to
execute and may use more resources.
|
A variable is a place to store a value in memory.
Each variable has an identifier, which is also called a name
or a handle, and a data type. If you define a variable
in your program, you can then use the name to access the
value later in the program. After you define a variable,
you can change its value unless it was declared as a constant,
whose value you cannot change.
Variables may be declared using the syntaxes
let and
def, which are described in more detail below. Variables may also
be introduced by other syntaxes such as
if-non-null or
in the case statements of
type-switch.
By declaring a variable, you are telling the runtime to reserve
memory and assign an initial value to the variable.
When you declare a variable, you specify the name of the
variable and the data type. The amount of memory that
the runtime allocates to the variable depends on the data type.
You can optionally initialize the value of the variable when you
declare it. If you do not initialize a variable, the runtime
assigns a default value to the variable. Variables defined using
the def syntax are required to have an explicit initializer.
If you do not declare the type of a variable, the runtime
automatically chooses a type. When the variable is declared
using
def, the type is inferred to be the same as the type of
the value assigned to it. When the variable is declared using
let, the type is the
any
data type. The
any data type can, as the name implies, store any
type of data.
The inclusion of the
any data type adds many features
to the Curl language. Because beginning
developers need not worry about type specifications, their
experience with learning to program in the Curl language is often easier.
Also, the migration to the Curl language for people who are used to
scripting languages that do not have type specifications
is easier. Many people argue that code is more readable
without type specifications. However, you should take care
because often there is a runtime cost associated with using
the
any data type. This means that, when your code
runs, it may take longer to execute and use more resources
if you have variables with the
any data type. See
The any Type section for
more information about the
any data type.
Because of the potential for typeless
let declarations to
result in somewhat slower code, the programmer may disable this
behavior by by setting the
allow-implicit-any-declarations?
compiler directive to false, which can also be accomplished by
setting one of the directives
fast?,
safe?,
careful? or
stringent? to true.
See the
Compiler Directives
chapter for details.
Once you declare a variable, the runtime ensures that you do not
assign a value that does not match the data type of the
variable. See the
Converting Data Types section for more information about conversion and
casting.
| Summary: | - Begin with a letter, ideographic character,
or an underscore character.
- Use only letters, ideographic characters,
digits, underscores, question marks, and hyphens.
- Identifiers are case-sensitive and width-sensitive.
|
An identifier is a name for a variable, procedure, class, or
anything else that someone can create in Curl language source
code. When choosing an identifier, use a combination of
characters that does not begin with a digit.
Identifiers can be written using a great many characters from the
Unicode® character set. Developers whose
native alphabet is not Roman can make use of most characters that
are used to write meaningful words in their language. For
example, Japanese developers may use kanji, hiragana, katakana,
Romaji, and ASCII characters in their variable names. Variables
are case-sensitive and width-sensitive.
In particular,
follow these rules when choosing identifiers:
- There is no limit to the number of characters in an
identifier.
- Begin with a letter, ideographic character,
or an underscore character.
- Use only letters, ideographic characters,
digits, underscores, question marks, and hyphens.
- Do not include spaces.
Click the following links to see examples of language specific
identifiers.
The syntax of the Curl language, unlike most other programming
languages, contains many special terms that are not technically
reserved words. It is therefore legal, though not advisable, to
use these Curl language terms as identifiers. For example, the
word field can be used when defining a class to reserve
room for a datum of a specified type within each instance of the
new type. In the Curl language, you can declare a variable with
the identifier field, or even use this word as the name of
a field for some class. However, although this is possible, it
makes code hard to read and harder to debug. Therefore we
recommend that you do not use Curl language commands and modifiers
as identifiers.
When creating identifiers, you can choose any valid identifier.
You should choose identifiers which help make your code easy to
understand for yourself and for other developers who may need to
read or maintain it. For consistency, we have adopted the
following guidelines for code written and maintained by developers
whose native script uses the Roman alphabet. Developers whose
native script uses ideographic characters, such as Japanese, may
wish to establish similar guidelines or conventions in their code.
| Type of Identifier | Guideline | Example |
| Package | Use all uppercase letters, with a hyphen between each word. | PACKAGE-NAME |
| Class | For each word, use an uppercase letter for the first character. | ClassName |
| Class Member | Use all lowercase letters, with a hyphen between each word. | class-member-name |
| Procedure | Use all lowercase letters, with a hyphen between each word. | procedure-name |
| Variable or Constant | Use all lowercase letters, with a hyphen between each word. | variable-name |
| Enumerated Type | For each word, use an uppercase letter for the first character. | MyType |
| Element of an Enumerated Type | Use all lowercase letters, with a hyphen between each word. | type-element |
| Summary: | - When choosing an identifier, do not use a
reserved word.
|
When choosing an identifier, do not use a reserved word.
The following are reserved words in this release of the Curl
language:
| ... | and | asa | construct-super | curl-file-signature | def | div | false | isa | let |
In addition, there are certain contexts in which defining
a variable with the name of a syntactic key word (other
than those listed in the table above) will make it impossible
for the runtime to parse your code. Examples of such contexts
include:
- Defining a class named public, package,
or protected.
- Defining a for iteration variable named
tag.
- Defining a local variable named else within
the then branch of an if expression.
You can declare global variables and constants only in
top-level code. (Remember that top-level code is code
that is not nested within another code block.) In an
applet, you must enclose the
let or
def statement
that declares global variables and constants in curly
braces. Otherwise, the runtime treats your
declaration as ordinary text and displays it. In a
package, you need not enclose the
let/
def statement
in curly braces, but as a matter of style we recommend using
them for global variables in order to distinguish them from
local variables declared using
let/
def.
The syntax of the
let/
def statement
for declaring a global variable or constant is as follows:
| Syntax: | {let [access] [modifier-list]
name[:type][ = value]}
or
{def [access] [modifier-list]
name[:type] = value}
|
|
|
| access | is the optional access attribute.
Valid attributes are public
and package. If you do not
specify access, the access
attribute defaults to package.
Specify public to declare a
public variable or constant. All
source code can access a public variable
or constant.
Specify package to declare a
package-protected variable or constant.
Only code in the same package can
access the variable or constant. |
| modifier-list | is the optional list of modifiers.
The only valid modifiers are
constant and deprecated.
Specify constant if you want
to declare a global constant. If you
specify constant, an explicit
value must also be provided
When using the def syntax, the
constant attribute is automatically
assumed and may not be explicitly specified.
Use deprecated if this global
variable or constant is not recommended
for use in new code and may be removed
in a future version. If you specify more than one
modifier, use spaces to separate the modifiers. |
| name | is the name of the variable or
constant. The Curl language naming conventions
for variables suggest using lowercase
letters and a hyphen to join multiple
words (for example,
variable-name). |
| type | is the data type of the variable
or constant. Specify any valid data
type. type is required if
value is not specified.
If type is not specified,
then any is assumed when using
the let syntax and is assumed to
be the same as the compile-time type of
value under the def syntax. |
| value | is the value of the variable or
constant. value is optional
for variables, but required for
constants. value is
required if type is not
specified. If value is not
specified, then null or 0
or false is assumed, as
appropriate. |
|
For example:
{let int-var:int = 4}
{let dbl-var:double}
{let constant int-const:int = 9}
{let constant char-const:char = 'a'}
{let public char-var:char}
{def pi = 3.14159}
Note: You can supply access and modifier-list
in any order. For example, both
let public constant ...
and
let constant public ...
are valid.
If multiple variables or constants have identical modifiers
and access attributes, you can use a single let/def
statement to declare them. Use the following syntax:
| Syntax: | {let [modifier] [access]
name[:type][ = value],
name[:type][ = value],
...
name[:type][ = value]
}
or
{def [modifier] [access]
name[:type] = value,
name[:type] = value,
...
name[:type] = value
}
|
For example:
{let public
int-var:int = 4,
dbl-var:double
}
{def public
int-const = 9,
char-const = 'a'
}
Within a code block, you can declare local variables and constants.
The scope of the variables is limited to the code block
in which they are declared. For local variables, the use
of curly braces to surround the let/def statement is
optional, and as a matter of style is discouraged.
A local variable defined using let can be declared as
constant, although it is usually easier to simply use
the def syntax. The syntax of the let/def
statement for declaring a local variable is as follows:
| Syntax: | let [constant] name[:type][ = value]
or
def name[:type] = {metvar value}
|
|
|
| name | is the name of the variable. The
Curl language naming conventions for variables
suggest using lowercase letters and
a hyphen to join multiple words (for
example, variable-name). |
| type | is the data type of the variable.
Specify any valid data type.
type is required if
value is not specified.
If type is not specified,
then any is assumed when using
the let syntax and is assumed to
be the same as the compile-time type of
value under the def syntax. |
| value | is the initial value of the
variable. value is required
if type is not specified.
If value is not specified,
then null or 0 or
false is assumed, as appropriate.
If the variable has the constant
attribute, you need to supply an initial
value. |
|
For example:
{do
let int-var:int = 4
let dbl-var:double
let char-var = 'z'
def message = "Hello World"
}
Also, you can use one let/def statement to declare
more than one local variable. Use the following syntax:
| Syntax: | let name[:type][ = value],
name[:type][ = value],
...
name[:type][ = value]
or
def name[:type] = value,
name[:type] = value,
...
name[:type] = value
|
For example:
{do
let int-var:int = 4,
dbl-var:double,
char-var = 'z'
def one = 1, two = 2
}
A class variable is like a global variable. However,
you also need to use the class name when referring to
the variable. Additionally, curly braces are optional
around the variable declaration, since it is not in
top-level code. When declaring class
variables, you can specify the usual access attributes
and modifier for class members. For more information,
see
Class
Constants, Variables, and Procedures.
The def syntax was introduced in version 6.0 of the Curl API. It
allows constants to be defined without having to explicitly specify the
type. The principle differences between let and def are
that def is implictly constant, def requires an explicit
value expression, and that the type is optional even
under stringent compiler directives. Instead of assuming the type is any, as would be the case when using let, the def syntax
instead infers the type from the value expression used to initialize the
constant(s). The inferred type is the compile-time type of the value
expression, not its runtime type; that is, it is the type that can be
determined when the value expression is compiled, where the actual runtime
value may be of a more specific type. For
def statements with one variable per initializer, the statement def name = value
is generally equivalent toFor example, the code-body def message = "hi"
def numbers = {IntVec 1,2,3,4}
is the same as let constant message:String = "hi",
let constant numbers:IntVec = {IntVec 1,2,3,4}
There is no equivalent for def (name1, name2) = values
since there is no syntax for computing the compile-time type of a
multi-value expression, but the principle is the same allowing you
to write code like: def (val, n-consumed) = {string.to-int}
Although, def declarations may specify explicit types,
there is usually no reason to do so.The following example demonstrates the difference between the implicit
types of the let and def syntaxes. The variable defined
using let will have an implicit type of any, while the
variable defined using def will have the type #String,
since that is what the hello proc is declared to return. The
actual runtime type of the value will be String in both cases.
| Example:
Implicit variable types with let and def |
 |
{define-proc {hello}:#String
{return "hello"}
}
{value
def def-s = {hello}
let let-s = {hello}
{format
"def-s type is '%s', let-s type is '%s'",
{compile-time-type-of def-s},
{compile-time-type-of let-s}
}
}
| |
| Summary: | - In top-level code, a variable definition
can access a variable that is defined later
in the same let expression.
- In a code block, a variable definition
can only access variables that are already
defined.
|
The let expression has slightly different scoping
characteristics in top-level code and within a code block.
In top-level code, a variable definition can access a
variable that is defined later in the same let
expression. However, in a code block, a variable definition
can only access variables that are already defined. For
example, the following declaration is legal in top-level
code but illegal in a code block:
The following code shows a let expression within a
procedure code block that generates a syntax error:
{define-proc public {qwerty}:int
let a:int=b,
b:int=0
{return a}
}
{qwerty}
SyntaxError: 'Attempt to access b inside its initializer.'
| Summary: | - The Curl language binds the value of expressions to variables
in a manner familiar to most developers.
- However, it creates anonymous procedures
without executing the body of the procedure itself.
- This means that you can refer to the variable
being defined within the anonymous procedure.
|
The Curl language has adopted some very powerful programming features
from the Lisp and Scheme programming languages. C++ and
Java™ programming language developers may not be aware of the full
implications of these features. One such programming
feature is the ability to create anonymous procedures in
the middle of other code (in other words, not at the top
level). Understanding and applying these programming
features correctly can provide tremendous flexibility
and power to Curl language developers.
The Curl language binds expressions to variables in a manner familiar
to most developers. If you use a
let statement
to declare and initialize a variable, like most
programming languages, the runtime evaluates the expression
that initializes the variable. This, of course, means
that you cannot use a variable in its own definition.
For example, the following code throws an error:
{value
let x:int = x + 1
}
SyntaxError: 'Attempt to access x inside its initializer.'
However, under certain circumstances, you can
refer to a variable within its definition. In particular,
you can refer to a variable when the reference to the
variable is within an anonymous procedure. (Anonymous
procedures are also known as
procs and are
described in the
Procedures chapter.) The value of an anonymous procedure
definition is the procedure itself. The body of the
anonymous procedure is not executed when the procedure
is defined, but when the procedure is used. Because the runtime
binds the anonymous procedure to the variable before
executing the body of the anonymous procedure, you can
refer to the variable within the anonymous procedure.
This has many useful applications.
One feature that makes implicit use of anonymous procedures
is the
on expression for specifying event handlers.
This means that the
on clauses in a variable definition can
refer to the variable being defined, allowing you to
perform tasks such as modifying the item being defined.
For example, the following code declares a button that
changes the test color when clicked. The
on expression in
the button declaration includes a reference to the
button.
The example first declares a variable
b with a data
type of
CommandButton and initializes
b with
an instance of the
CommandButton class that changes its
text color to red when clicked. To do this, the action clause of
the button declaration refers to the variable being declared.
| Example:
Using a Variable in its Own Definition, Part 1 |
 |
{let b:CommandButton =
{CommandButton label="I like red",
{on Action do
set b.color = "red"
}
}
}
|| Display "b".
{value b}
| |
By allowing you to create an anonymous procedure before
executing the procedure's body, the Curl language provides you
with a very powerful programming feature. However, in
order to use this programming feature correctly, you
must be aware of the value of the expression when it
is finally executed. This issue can be particularly
complicated when different anonymous procedures are
created on each iteration of a loop, but with each
procedure referring to the same variable defined
outside the loop. The remainder of this section
provides examples that illustrate these issues.
The following example shows a
for loop that,
for each iteration through the loop, adds the loop index
variable to a
VBox. The
VBox contains
the value of the loop index variable for each iteration.
| Example:
Using a Variable in its Own Definition, Part 2 |
 |
{value
|| Declare and initialize a VBox "message".
let message:VBox = {VBox}
|| For each iteration through the loop, add the loop
|| index to "message".
{for index:int = 0 to 3 do
{message.add index}
}
|| Display "message".
{value message}
}
| |
The next example, however, probably generates output that
you do not expect. For each iteration through the loop,
this example adds a button to a VBox. The labels
on the buttons include the value of the loop index
variable. When you click on a button, this example adds
the value of the loop index variable to the display of
another VBox. However, this example illustrates
an unexpected consequence of the way that the runtime binds
anonymous procedures to variables within a loop when the
expression contains a variable that is declared outside
of the scope of the loop.
The runtime binds the
on expression of the
CommandButton
declaration without evaluating the expression. When you
click one of the resulting
CommandButtons, the runtime evaluates
the
on expression, which adds the loop index variable
to the
VBox. However, the loop has terminated and
the loop index variable is set to the value that caused the
loop to finish executing. The value of the loop index
variable that terminated execution of the loop is added to
the
VBox regardless of the
CommandButton that is
clicked.
| Example:
Using a Variable in its Own Definition, Part 3 |
 |
{value
|| Declare and initialize two VBoxes; "buttons" and
|| "message".
let buttons:VBox = {VBox}
let message:VBox = {VBox}
|| For each iteration through the loop, add a CommandButton
|| to "buttons".
{for index:int = 0 to 3 do
|| If you click on the CommandButton, add the loop index
|| to "message".
let b:CommandButton = {CommandButton label="index is... " & index,
{on Action do
{message.add index}
}
}
{buttons.add b}
}
|| Display "buttons" and "message".
{VBox
{value buttons},
{value message}
}
}
| |
To obtain the intended result, create a variable within
the scope of the for loop that will hold the
value of the loop index variable and use this variable
in the on expression. Because the variable is
declared within the scope of the for loop, a copy
of the variable will be maintained for each iteration
through the loop. Then, when the on expression
is evaluated, the runtime will use the appropriate copy of the
variable for that CommandButton.
| Example:
Using a Variable in its Own Definition, Part 4 |
 |
{value
let buttons:VBox = {VBox}
let message:VBox = {VBox}
{for index:int = 0 to 3 do
|| Declare an int "temp" and initialize it to
|| the value of "index"
let temp:int = index
|| If you click on the CommandButton, add the
|| value of "temp" to "message".
let b:CommandButton = {CommandButton label="index is... " & temp,
{on Action do
{message.add temp}
}
}
{buttons.add b}
}
{VBox
{value buttons},
{value message}
}
}
| |
To further illustrate this issue, consider the situation
where the variable is instead declared outside of the
for loop, but updated for each iteration within
the loop. Again, because this example evaluates the
on expression when the CommandButton is clicked,
the current value of the variable is added to the display
of the VBox (and not the value of the variable
when the CommandButton was created).
| Example:
Using a Variable in its Own Definition, Part 5 |
 |
{value
let buttons:VBox = {VBox}
let message:VBox = {VBox}
|| Declare an int "temp"
let temp:int
{for index:int = 0 to 3 do
|| Assign the value of "index" to "temp"
set temp = index
let b:CommandButton = {CommandButton label="index is... " & temp,
{on Action do
{message.add temp}
}
}
{buttons.add b}
}
{VBox
{value buttons},
{value message}
}
}
| |
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.