Procedures and Event Handlers

Procedures: Subs and Functions

Tibbo BASIC offers two kinds of procedures: subs, which are procedures that do not return a value (directly), and functions, which are procedures that do return a value.

Both subs and functions can have arguments.

The parallel structures in Tibbo C are a void function and a non-void function.

You must always specify the return type for the function. We do not allow omitting this.

Tibbo BASIC
Tibbo C
sub fill_the_screen(color as word)
   lcd.forecolor=color
   lcd.fill(0,0,lcd.width,lcd.height)
end sub

function sum_total(a as word, b as word) as word
   sum_total=a+b 'this is how you return a value from a Tibbo BASIC function
end function
void fill_the_screen(unsigned int color){
   lcd.forecolor=color;
   lcd.fill(0,0,lcd.width,lcd.height);
}

unsigned int sum_total(unsigned int a, unsigned int b){
   return a+b;
}

Notice how the BASIC function returns the value: a function named sum_total will have a local automatically created variable with the same name. Set this variable to the desired return value.


Procedures Must Be Defined or Declared Before Use

In Tibbo BASIC/C, procedures must be defined or declared before they are used.

The procedure definition is its body. Place the body above the first call to this procedure, and there is no need for a declaration:

Tibbo BASIC
Tibbo C
function sum_total(a as word, b as word) as word
   sum_total=a+b
end function

sub on_sys_init
   dim i as word=sum_total(10,20)
end sub
unsigned int sum_total(unsigned int a, unsigned int b){
   return a+b;
}

void on_sys_init(){
   unsigned int i=sum_total(10,20);
}

If a procedure is called first and defined later, place a declaration before the first call:

Tibbo BASIC
Tibbo C
declare function sum_total(a as word, b as word) as word

sub on_sys_init
   dim i as word=sum_total(10,20)
end sub

function sum_total(a as word, b as word) as word
   sum_total=a+b
end function
unsigned int sum_total(unsigned int a, unsigned int b);

void on_sys_init(){
   unsigned int i=sum_total(10,20);
}

unsigned int sum_total(unsigned int a, unsigned int b){
   return a+b;
}

As each source code (and HTML file) is compiled separately, it is necessary to declare procedures defined in other files before they can be called. Such declarations are usually placed in header files.TPH for Tibbo BASIC and .TH for Tibbo C. Header files must be included into your source code file; it's not enough to simply have them in the project tree:

Tibbo BASIC
Tibbo C
include "global.tbh"
#include "global.th"

Event Handlers

Event handlers are subs in Tibbo BASIC and void functions in Tibbo C. These require no declaration because they are already declared in platform files.

Whenever the VM gets to handling a certain event, it calls the corresponding event handler for this event, provided such handler exists in your code.

Tibbo BASIC
Tibbo C
sub on_sys_init
   'always called once on boot
end sub

sub on_sys_timer
   'called periodically (by default, at 0.5 second intervals)
end sub
void on_sys_init(){
   //always called once on boot
}

void on_sys_timer(){
   //called periodically (by default, at 0.5 second intervals)
}

How do you tell if a procedure is an event handler or not? Names of event handlers are highlighted in green. Additionally, all event handler names start with on_, which means on x happening, do....


The list of available events can be found in the Browser-Project pane: View > Browser-Project -> Events.


An additional information note icon.Inactive events (those with no event handlers) are grayed out. Double-click on an inactive event to add its event handler to the bottom of the current file.

Double-click on an active event to "teleport" to this event handler's body.


Events are actually a part of platform objects. For more information, see Objects and Syscalls.


Direct Argument Passing

In Tibbo BASIC, procedure arguments can be passed by value (ByVal) or by reference (ByRef). ByVal is the default mode, so you don't have to specify it.

The ByVal argument passes a copy of the value. If the procedure called modifies this value, then only that copy is modified and the original instance stays the same.

The equivalent of this in the C world is passing an argument and not a pointer to this argument.

Tibbo BASIC
Tibbo C
sub print(i as word) 'you could write "sub print(ByVal i as word)"
   sys.debugprint(str(i)+chr(13)+chr(10))
end sub
void print(unsigned int i){
   sys.debugprint(str(i)+chr(13)+chr(10));
}

In Tibbo BASIC and C, even "bulky" items can be passed directly.

For Tibbo BASIC, such bulky items are string variables and types (structures). For Tibbo C, these are string variables, arrays, structures, and unions.

Have you noticed? Arrays are not listed for BASIC! In Tibbo BASIC it's not possible to pass an array to a sub/function or return an array from a function.


Here is an example of a function that increments each member of an array and then returns the array back. Since arrays cannot be passed to/from BASIC procedures, the BASIC code example below wraps an array into a type.

Notice a very interesting syntax that is used to specify that the C functions returns an array.

Tibbo BASIC
Tibbo C
'TERRIBLY INEFFICIENT but will work!
type type_a
   arr(5) as byte
end type

function arr_increment(input as type_a) as type_a
   dim f as byte
   for f=0 to countof(input.arr)-1
      input.arr(f)=input.arr(f)+1
   next f
   arr_increment=input
end function

sub on_sys_init()
   dim master_arr as type_a
   ...
   master_arr=arr_increment(master_arr)
end sub
//TERRIBLY INEFFICIENT but will work!
unsigned char arr_increment(unsigned char input[5])[5]{
   //the highlighted [5] above specifies that this function returns an array 
   unsigned char f;
   for(f=0;f<sizeof(input);f++)
      input[f]++;
   return input;
}

void on_sys_init(){
   unsigned char master_arr[5];
   ...
   master_arr=arr_increment(master_arr);
}

Indirect Argument Passing

In Tibbo BASIC, a ByRef argument passes a reference to the value. If the procedure called modifies this argument, then the original instance gets modified.

This is roughly equivalent to using a pointer in C, except the pointer itself is not available to the BASIC code and can't be modified by it.

ByRef argument passing in BASIC and pointers in C are recommended for bulky types. This saves memory and improves performance.

ByRef/pointers can also be used to indirectly return a value from a procedure (void function).


Here is the previous array increment example, now rewritten to use a ByRef argument and a pointer. It is much more efficient as no unnecessary copying takes place.

Tibbo BASIC
Tibbo C
type type_a
   arr(5) as byte
end type

sub indir_arr_increment(byref input as type_a) 
   dim f as byte
   for f=0 to countof(input.arr)-1
      input.arr(f)=input.arr(f)+1
   next f
end sub

sub on_sys_init()
   dim master_arr as type_a
   ...
   indir_arr_increment(master_arr)
end sub
void indir_arr_increment(unsigned char *ptr,unsigned char len){
   unsigned char f;
   for(f=0;f<len;f++)
      (*ptr++)++;
}

void on_sys_init(){
   unsigned char master_arr[5]};
   ...
   indir_arr_increment2(&master_arr,sizeof(master_arr));
}

Tibbo BASIC and C will never automatically switch to using the ByRef (pointer) method instead of passing the value itself.

Some languages practice automatic switching whenever there is a bulky item to pass. For example, there are systems that won't pass a structure directly and won't tell you about the substitution that took place.

We consider this to be extremely misleading. In Tibbo BASIC (and C), "what you define is what you get."


No Recursion, Re-Entrant Code, or Function Pointers

Tibbo BASIC and Tibbo C do not allow recursion. Meaning: procedures cannot call themselves (even indirectly).

It is also not possible to create re-entrant functions.

Additionally, pointers to functions are not allowed in Tibbo C.

All of this has to do to how the memory is allocated for procedures.


Procedures and Event Handlers

Procedures: Subs and Functions

Procedures Must Be Defined or Declared Before Use

Event Handlers

Direct Argument Passing

Indirect Argument Passing

No Recursion, Re-Entrant Code, or Function Pointers