Procedures and Event Handlers

Top  Previous  Next

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.

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 Project Browser pane: View > Project-Browser -> Events.

 

note_further-wtInactive events (those with no event handlers) are grayed. 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, the subject of the Objects and Syscalls section.

 

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.

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 the 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
  ...
  master_arr=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, reentrant 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.