Variables
When your program code works with data types, it always accesses them using variables. You can think of variables like little boxes that store some information, such as a number. The kind of information is the variable's data type. Variables always have a name (the identifier) such as X or NUMBER_OF_COINS. If you are familiar with the Chombit CPU, you can also think of a variable as a name for a memory address that stores some data.
The Hybrix language has four basic kinds of variables:
1. Local variables
Local variables are declared inside a FUNC or HOOK definition, using the VAR keyword:
MODULE MAIN
FUNC START()
# "X" IS A LOCAL VARIABLE INSIDE THE FUNCTION "START()"
# WHICH IS A MEMBER OF THE MODULE "MAIN".
VAR X: INT
123 --> X
# DEFINE TWO VARIABLES "Y" and "Z".
VAR Y: BYTE, Z: BYTE
# THIS IS EQUIVALENT TO "VAR I: INT"
VAR I
END FUNC
END MODULE
The VAR definition must come before any statements that reference its variable, in the current block or a parent block. For example:
MODULE MAIN
FUNC START()
IF TRUE THEN
1 -> X # ⚠️ ERROR: "VAR" DOES NOT PRECEDE "X"
VAR X: INT
IF TRUE THEN
2 -> X # THIS IS OKAY
END IF
ELSE
3 -> X # ⚠️ ERROR: "VAR" IS IN A SIBLING BLOCK
END IF
END FUNC
END MODULE
The data type (INT, BYTE, etc.) comes after the colon (:). If you omit the colon and type, the compiler makes it an INT.
⭐ Local variable memory storage
Local variables are stored as registers on the Chombit CPU stack. This way, they do not consume any memory unless the function is being called. If the function is called again before it finishes (for example, if the
FUNCcalls itself recursively), then the same variable can have multiple allocations at once. In other words, each function call gets its own copy of the local variables.You must initialize a variable (for example,
123 --> X) before you can read its value (for example,X + 1 --> X).
2. Function parameters
Function parameters appear inside the ( ) of a FUNC definition, without the VAR prefix. In the example below, WIDTH and HEIGHT are function parameters:
MODULE RECTANGLE
# "WIDTH" AND "HEIGHT" ARE FUNCTION PARAMETERS:
FUNC GET_AREA(WIDTH: INT, HEIGHT: INT): INT
VAR AREA: INT
WIDTH * HEIGHT -> AREA
RETURN AREA
END FUNC
END MODULE
Function parameters behave exactly like local variables, except that their initial value is provided by the caller of the function. For example, if the function call is RECTANGLE::GET_AREA(2,3), then the function will start with WIDTH equal to 2, and HEIGHT equal to 3.
You are allowed to change the value of a parameter like WIDTH inside the function, using it like a local variable:
MODULE RECTANGLE
FUNC GET_AREA(WIDTH: INT, HEIGHT: INT): INT
# STORE THE RESULT BACK INTO "WIDTH", OVERWRITING THE OLD VALUE:
WIDTH * HEIGHT -> WIDTH
RETURN WIDTH
END FUNC
FUNC GET_SQUARE_AREA(SIDE: INT): INT
VAR AREA
# ALTHOUGH THE "SIDE" VALUE GOES INTO "WIDTH" ABOVE,
# OVERWRITING "WIDTH" WILL NOT AFFECT "SIDE"
RECTANGLE::GET_AREA(SIDE, SIDE) -> AREA
RETURN AREA
END FUNC
END MODULE
⭐ Function parameter memory storage
Function parameters are also stored as registers on the Chombit CPU stack, just like local variables. The only difference is that the function's caller always initializes them.
3. MODULE member variables
Variables can also go inside a MODULE definition, for example:
MODULE GAME_BOARD
# THE FULL NAME WILL BE "GAME_BOARD::INITIALIZED"
VAR INITIALIZED: BOOL
FUNC INIT()
# IF INIT() WAS ALREADY CALLED, DON'T INITIALIZE AGAIN
IF GAME_BOARD::INITIALIZED
DO RETURN
TRUE --> GAME_BOARD::INITIALIZED
# (MORE CODE HERE)
END FUNC
END MODULE
In the above example, GAME_BOARD::INITIALIZED is a module member variable, sometimes
called a global variable. Unlike local variables, module variables always exist and
cannot have multiple copies. When you access them, you must use the :: operator to indicate
the module. As a result, you could also have a local variable called INITIALIZED without
confusion. The same variable name can also be reused in other modules without confusion:
MODULE GAME_BOARD
# THE FULL NAME WILL BE "GAME_BOARD::INITIALIZED"
VAR INITIALIZED: BOOL
FUNC INIT()
VAR INITIALIZED: BOOL
# "INITIALIZED" AND "GAME_BOARD::INITIALIZED" ARE TWO DIFFERENT VARIABLES:
TRUE --> GAME_BOARD::INITIALIZED
FALSE --> INITIALIZED
END FUNC
END MODULE
MODULE MUSIC_LIBRARY
# THE FULL NAME WILL BE "MUSIC_LIBRARY::INITIALIZED"
VAR INITIALIZED: BOOL
END MODULE
Any FUNC can access module variables, even if the FUNC belongs to a different module or a class. If that was not your intention—if the variable is meant to be private to its module—you can add an _ prefix to indicate that. For example:
MODULE GAME_BOARD
# OTHER MODULES SHOULD NOT READ OR WRITE THIS MEMBER:
VAR _INITIALIZED: BOOL
# OTHER MODULES CAN ASSIGN "VISIBLE" TO CONTROL WHETHER THE
# GAME BOARD WILL BE RENDERED:
VAR VISIBLE: BOOL
END MODULE
⭐ Module variable memory storage
Module member variables are stored in the Chombit heap memory, in a special memory block that holds all the members of all modules. When the program starts up, this memory is reset to all zeroes:
BOOLvariables will start out asFALSE,INTvariables will be0, pointers will beNULL, and so forth.
4. CLASS member variables
Variables can also go inside CLASS definition, for example:
CLASS RECTANGLE
# "X" AND "Y" ARE MEMBER VARIABLES OF "RECTANGLE":
VAR X: INT, Y: INT
FUNC GET_AREA(): INT
VAR AREA: INT
# WHEN ACCESSING THEM INSIDE "RECTANGLE", WRITE ".X" OR ".Y"
.X * .Y --> AREA
RETURN AREA
END FUNC
END CLASS
MODULE MAIN
FUNC START()
VAR MY_RECT: RECTANGLE, AREA: INT
NEW RECTANGLE() -> MY_RECT
# WHEN ACCESSING THEM FROM ANOTHER CLASS OR MODULE,
# USE THE VARIABLE NAME FOLLOWED BY ".X" OR ".Y":
10 --> MY_RECT.X
20 --> MY_RECT.Y
MY_RECT.GET_AREA() --> AREA
END FUNC
END MODULE
Class members must always be accessed using the . prefix. For example, .X (for code inside the class) or THING.X (for code outside the class). This means that you can have a local variable called X and a member variable called .X without confusing them.
⭐ Class variable memory storage
Class member variables are stored in the Chombit heap memory, in a normal heap block that is allocated by
NEW. In the above example,NEW RECTANGLE() -> MY_RECTcreates a new instance of theRECTANGLEclass, allocating a heap block. Thus, you can have many instances of a class, and each instance will get its own separate.Xand.Ystorage.Newly allocated memory is reset to all zeroes:
BOOLvariables will start out asFALSE,INTvariables will be0, pointers will beNULL, and so forth.The Hybrix garbage collector automatically frees the heap block when it is no longer used, for example if
NULLis assigned toMY_RECT.