2. Data Types and Variables
GSL has 9 basic data types. In addition, new user defined data types can be created using the typedef / extends syntax. GSL has 9 basic data types:
GSL is case insensitive for the first letter of the basic variable types. So Int is the same as int for example, so people can adapt faster from their language of choice. However, GSL is not case insensitive for self defined types. As a coding convention, self defined types should start with an upper case letter. Note about the object type: It is used by some system calls. You cannot create object instances with a constructor, you can only get any by calling a system call that returns an object (or some type derived from it) and they are just useful to get handed back to other system calls. Struct and array are the storage types in GSL which can store other variables. Note that array and struct types are initialized with null, not a new array/struct. So if you want an array/struct variable to contain an instance of the type, you have to assign a constructor to it first (see next section). The literals in GSL are more or less like the literals in most other languages: Following literals exist for the data types:
Each variable you want to use in GSL has to be declared before it can be used. In GSL, there exist two different types of variables globals and locals. The syntax of a local declaration is like that TYPENAME VARIABLENAME;
This declares the local variable <VARIABLENAME> of type <TYPENAME>.
So if you want to declare a new local variable of type int, named foo, you write:
int foo;
Local variables are only visible in the block where they were defined. If you want a variable to be visible in your whole script you have to declare it global by writing the keyword global in front of its declaration: global TYPENAME VARIABLENAME;
These variables will be visible everywhere, even in functions.
There may be no two local or global variables with the same name visible at one time. However, there may be a global variable with the same name as a local variable. In this case, the local variable will override the global. Examples: global int i;
int i; //Possible, local and global with same name allowed
int i;
int i; //Not allowed: Two locals/globals with the same name
Variable can also be initialized explicitly upon declaration, which this syntax: TYPENAME VARIABLENAME = INITIAL_VALUE;
So if you want to declare a new variable of type int, named foo and assign the value 10 to it, you write:
int foo = 10; If a variable isn't initalized explicitly, it is initialized with the default initial value of the given variable type. The inital values are the following:
You can get a new instance of every data type (also self defined ones!) except var and object by calling TYPENAME() The constructor of the 4 basic types int,float,bool,string just returns their initial value as stated in 4.4. Concerning arrays, the constructor will give you a new array, with no keys/values assigned yet. Concerning struct types, the constructor will generate a new struct, initialize all members with their initial values and give you a reference to that struct. Objects and Vars cannot be instanciated using a constructor because: objects may only be generated by internal system calls, not the script itself, since they represent internal JAVA objects the type var is a variable type, it can hold any other type but cannot be instanciated itself. here are some examples for the usage of a constructor int foo = int(); //foo is 0 now, not very useful, since you could also write int foo = 0;
array a = array(); //a contains a new, empty array now. Struct denotes a structure type, as known from other languages like C. A structure is a variable that contains several other variables called members. The name, type and the initial value of these members is defined in the struct's definition. Structs are defined like that: typedef TYPENAME struct{
TYPE1 NAME1;
TYPE2 NAME2 = INIT_VALUE;
...
}
As you can see the definition starts with the keyword "typedef" which always denotes a new type definition. Typedef is followed by the desired name of your struct type <TYPENAME>. After that, the word struct follows. Then, there is a list of member declarations, surrounded with curly braces. Each member must have a name and a type and can have an initial value. When a struct is created using the constructor TYPENAME() all members are initialized with the given values or with the default values. As you see you have to define structs by yourself. The type struct itself also denotes a structure, but the one with no members. However, all self defined structs are considered to be extended from struct. So you can put any self defined array into a variable of type struct. The constructor struct() will give you an instance of this type. However this instance ain't usesful since it has no members and thus can contain no data at all. Normally struct members are accessed by using the . operator like this: STRUCTVAR.MEMBERNAME
Here is an example of the usage of a self defined struct: typedef Point2D struct{ //Define the struct point as a 2 dimensional coordinate
int x;
int y;
}
Point2D myPoint = Point2D(); //Create a new point
myPoint.x = 5; //Assign 5 to the x coordinate
myPoint.y = 7; //Assign 7 to the x coordinate The type array in GSL denotes an associative array (also called hash), which can hold key value pairs. The keys can either be of type int and/or of type string, the values can be of any type (even different types in one array are allowed). An array is created by calling the constructor array(). A freshly created array has no key value pairs yet. You can access the values using the array index syntax (like in most common languagues): ARRAYVAR[KEY]
Here is an example: array a = array(); //Declares the array variable a and assigns a new array to it
a[0] = "foo"; //Saves the string value "foo" under the int key 0
a["bar"] = true; //Saves the bool value true under the string key "bar"
a[45] = 34; //Saves the int value 34 under the int key 45
a["xx"] = array(); //Saves a new array under the string key "xx" Arrays written in the last chapters, arrays entries are normally accessed using the a[ b ] syntax and struct members using the a.b Syntax. However, in GSL you can exchange both. So a.b is semantically equivalent with a["b"]. This is useful to iterate over struct members using the foreach loop. The [] syntax is generally mightier than the . syntax since it allows choosing the member during runtime by using string variables as indices. But note that this works only for string keys, not int keys ,so a[0] can't be replaced by a.0 . Examples: typedef Point2D struct{
int x;
int y;
}
Point2D myPoint = Point2D();//Create a new point
myPoint.x = 5; //Assign 5 to the x coordinate
myPoint["x"] = 5; //Same as the line above
array a = array();
a["foo"] = "bar"; //Assigns "bar" to the key "foo"
a.foo = "bar"; //Same as above Typecasting has to be done, when a variable of type a has to be assigned to a variable of type b or two values of different types are put together with a binary operator. Implicit typecasting is done in GSL for the following types: Int can be cast implicitly to float. Everything can be cast implicitly to string. This is a very useful functionality, since casting structs or arrays to string returns a string that shows all content. This is very useful for debugging purposes. Example: array a = array();
a[0] = "foo";
a[3] = 345;
a[5] = array();
string s = a;
s now contains now this string: array( 0 => foo 3 => 345 5 => array() ) For derived or struct types implicit typecasting is done if a type (child) which is derived from another one (ancestor) is cast to the ancestor type (also called upcasting). Since any defined struct is derived from the type struct itself, you can cast every struct type to struct implicitly: typedef Point2D struct{
int x;
int y;
}
Point2D myPoint = Point2D();
struct s = myPoint; //Possible since Point2D as a struct type is derived from struct
If a type can't be casted implicitly to another you can still try to cast it explicitly using the cast operator (TYPENAME)VAR_TO_CAST
(Exactly the same like in java/c)
These types can be casted explicitly: -Everything that can be casted implicitly (of course) -Bool can be casted to int or float, which results in 1 / 1.0 for true and 0 / 0.0 for false -Int and float can be casted to bool which returns VALUE != 0 -Float can be casted explicitly to int. The floating point number is then rounded down to the next integer number -String can be cast to bool, float and int which result in the string beeing parsed. If the string cannot be parse, it will throw an error -Derived types can be cast from ancestor to child type (called downcasting). If the variable isn't of the child type, you will get an error. Examples: Number casting: float f = 2.999;
int i = (int)f; //i is 2 now
String casting (parsing): string s1 = "25.34";
float f = (float)s1; //f is 25.34 now
string s2 = "true";
bool b = (bool)s2; //b is true now
string s = "2z4";
int i = (int)s; //Error, "2z4" is no integer representation
Up- and Downcasting: typedef Point2D struct{
int x;
int y;
}
typedef Size struct{
int width;
int height;
}
struct s = Size(); //Implicit "upcast"
Size t = (Size)s; //Explicit "downcast"
Point2D = (Point2D)s; //Error: the content of s is of type Size, not of Point2D thus cannot be cast
|