Variables and functions are declared in Slick-CŪ the same way they are defined in C.
This section contains the following topics:
The Slick-CŪ language supports global, namespace, static (module), and local scope variables. Global variables can be accessed by any module. The scope of static and local variables are limited to the module in which they are defined. Variables are declared the same way that they are defined in C++. See Types for a list of types available in Slick-C.
Namespace level variables are visible within the current namespace but can be accessed from another namespace if they are qualified with the namespace name or imported with the using directive.
The syntax for defining a simple variable is:
[static] TypeName variable1[=expression1] , variable2[=expression2] ...;
The comma is used to declare more than one variable of the same type. Local variables do not have to be defined. Using a variable not already defined as global or constant declares the variable to be a local typeless variable. However, you should declare variables within the scope of a function to ensure that the variable will be local even if the name is declared elsewhere as a global or constant.
Example:
// Declare a global integer.
int gi=1;
// Declare a module scope integer.
static int si=2+4;
// Declare some global string variables.
_str gstring1="Value1", gstring2="Value2";
// Declare a global large floating point variable.
double gd=1.4;
// Declare a global typeless variable.
typeless gt="xyz";
defmain( )
{
_str s="ess";
// Declare a local string variable and initialize it to "ess".
t=gi;
// Copy gi into local container variable t.
message("t="t"s="s);
}The following are some details about variable initializations:
Global and static numeric variables, which include boolean, int, long, double, and enumerated types, are initialized to 0 when there is no specified value provided. Local variables of any type are not initialized.
Global and static variables declared as typeless or _str are initialized with "" (a zero length string) when there is no initialization value provided.
Global, static, and local variables declared as array, hash tables, and structure types are initialized as empty when there is no initialization value provided.
Global, static, and local variables of class type are initialized by running their constructor with default arguments. Global, static, and local variables of interface type are initialized to null.
Local numeric, string, enumerated, and typeless variables require initialization.
Example:
boolean globalboolean=true;
int globalint;
double globaldouble;
defmain()
{
// Will print message "globalboolean=1 globalint=0 globaldouble=0".
message("boolean="globalboolean" "globalint" "globaldouble);
}Slick-CŪ enforces string type checking on everything except typeless variables. However, there are times when you need to convert an expression from its actual type to another. Type casting helps communicate that to the compiler. Note that some type conversions can change the value of an expression. The syntax for type casting is as follows:
(TypeName) expression
Some casts are not permitted in Slick-C. For example, you cannot cast a struct type to another struct type. Also, Slick-C does not support the C++ function style cast mechanism, and does not permit pointer types to be cast.
Example:
defmain()
{
int i;
double d;
d=1.2;
i=(int)d; // i gets the value 1, NOT 1.2
typeless t;
t=1.2;
i=t; // Here i gets 1.2 BUT
boolean b;
b= i!=0; // Can't use cast here.
i=(int)b; // Need cast here.
}Local variables do not have to be declared. Using a variable not already declared as global or constant declares the variable to be a local typeless variable. However, you should declare variables within the scope of a function to ensure that the variable will be local even if the name is declared elsewhere as a global or constant. Turning on any of the compiler pragmas autodeclvars, strict, or pedantic will flag implicit local variables as errors.
Example:
_str cheese1 = "provolone"; _str cheese2 = "cheddar"; temp = cheese2; // Same as typeless temp = cheese2; cheese2 = cheese1; cheese1 = temp;
Slick-CŪ supports type inference using the := operator, which both declares, and initializes a local variable with inferred type. This syntax provides you with the syntactic convenience of implicit local variables without sacrificing strong type checking.
In the following statement, id is declared as a local variable with the same type as expr:
id := expr;
Examples:
b := false; // boolean b = false; i := 0; // int i = 0; j := i; // int j = i; s := "test"; // _str s = "test"; p := &s; // _str *p = &s; c := _process_comment(line); // COMMENT_TYPE c=_process_comment(line); p := &obj; // Object *p = &obj; fp := func; // int (*fp)() = func; x := y := 0; // int x=0; int y=0; for (a:=1; a<10; ++a); // count to 10
Slick-CŪ supports type inference using the auto keyword. The syntax for auto variable declarations is:
[static] auto variable1[=expression1] , variable2[=expression2] ...;
Like the := operator, auto variable declarations use type inference to assign a type to the variable being declared and initializes the variable with the specified expression. Auto declarations are allowed in both local and global scopes, whereas := can only be used inside functions for local declarations.
Examples:
auto b=false; // boolean b=false; auto x=0, y=1; // int x=0; int y=0; auto i=x+1, s="test"; // int i=x+1; _str s="test";
You can also use auto to introduce a new local variable when calling a function that takes an "out" argument by reference, or with the parse statement. You can think of this identical to using implicitly declared variables, except that you prefix the variable with the auto keyword to introduce it. The type of the variable will be inferred from the point of use. In a parse statement, it will become a string type. In a function call, it will acquire the type of the formal argument from the function prototype. The advantage of using auto for output-only pass by reference variables is that, when coding a function call, you do not have to backtrack to declare the variable, you can just introduce it at its point of use and keep coding.
Examples:
struct Position {
double x,y,z;
// ...
};
struct SpaceTimeContinuum {
_str timeVal;
// ...
};
void warp(SpaceTimeContinuum &stc)
{
// ...
}
void travelFast(Position destinations[])
{
warp(auto stc);
parse stc.timeVal with auto realPart'+'auto imaginaryPart;
// ...
foreach (auto p in destinations) {
// ...
}
}