Other Features - BBpezsgo/BBLang GitHub Wiki

Other Features

Some features that are exists in some languages.

Extension functions

You can define an extension function as follows:

i32 add(this i32 a, i32 b) {
  return a + b;
}

If the first parameter defined with the this modifier, the function can be called like this:

i32 sum = 57.add(2);

You can also call an extension function in a normal way:

i32 sum = add(57, 2);

new statement

You can use the new keyword to initialize a value. This is used for structs and arrays.

// Creates a new struct Point and initializes it to zeroes
Point point = new Point;

You can also use the new keyword to allocate memory on the heap:

// This will allocate a new struct Point on the heap
Point* point = new Point*;
// This will allocate an integer on the heap
i32* value = new i32*;
// This will allocate 5 bytes on the heap
u8[]* value = new u8[5]*;

delete statement

You can use the delete keyword to deallocate a value from the heap.

// Allocate an integer on the heap
i32* value = new i32*;

// Deallocate the integer from the heap
delete value;

If there is a constructor defined for the type, that will be called before deallocating the object.

Constructors

You can define a constructor for a struct like this:

struct Point
{
  i32 x;
  i32 y;

  Point(i32 x, i32 y)
  {
    this.x = x;
    this.y = y;
  }
}

And use it like this:

Point point = new Point(37, 81);

Note that if you don't put the parentheses here, you just initialize a value without calling a constructor.

You can think of a constructor like this:

Point point = new Point; // Initializing with zeros
ctor(point, 37, 81); // Calling the corresponding constructor

You can also define multiple constructors for different kind of types:

struct Point
{
  i32 x;
  i32 y;

  Point(i32 x, i32 y)
  {
    this.x = x;
    this.y = y;
  }

  Point*(i32 x, i32 y)
  {
    this.x = x;
    this.y = y;
  }
}

And use them like this:

Point point1 = new Point(37, 81); // This is on the stack
Point* point2 = new Point*(37, 81); // This is on the heap

If there is one constructor defined, that will be used whatever type you want to allocate.

struct Point
{
  i32 x;
  i32 y;

  Point(i32 x, i32 y)
  {
    this.x = x;
    this.y = y;
  }
}

// These two will call the same constructor
Point point1 = new Point(37, 81);
Point* point2 = new Point*(37, 81);

Destructors

You can also define a deconstructor for a struct like this:

struct List
{
  i32[]* _ptr;

  destructor()
  {
    delete this._ptr;
  }
}

The destructor called before deallocating the object.

Index getters & setters

You can define a custom indexer for a struct like this:

struct List
{
  i32[]* _ptr;

  i32 indexer_get(i32 index)
  {
    return this._ptr[index];
  }

  void indexer_set(i32 index, i32 value)
  {
    this._ptr[index] = value;
  }
}

And use it like this:

// This is on the stack
List list1 = new List;
list1[4] = 7;
int v = list1[4];

// This is on the heap
List* list2 = new List*;
list2[4] = 7;
int v = list2[4];