Reflect

Structs

⚠️ TODO

Example

struct Vec2 {
	var x: float;
	var y: float;

	method getLength() => sqrt(this.x ^^ 2 + this.y ^^ 2);
}

var v = Vec2(3.0f, 4.0f);
print(v.getLength()); // 5

Constructor and Destructor

⚠️ TODO

Example

struct S {
	var coords: int[];

	this(x: int, y: int)
	{
		coords = allocArray(int, 2);
		coords[0] = x;
		coords[1] = y;
	}

	~this()
	{
		freeArray(coords);
	}

	@disable operator[copy]();
}

Copy and Move Operators

The behavior of a struct value being copied or moved by the compiler can be customizing by overloading the copied and moved operators.

The copied operator will be called whenever a value was copied to a new memory location. It allows the struct to perform bookkeeping tasks, such as incrementing a reference count.

The moved operator is called similarly after a value has been moved to a different memory location.

Both operators can be marked with the @disable attribute do disallow copying or moving values of the respective struct type.

Example

struct S {
	operator[copy]() {
		print("copied!");
	}

	operator[move]() {
		print("moved");
	}
}

struct T {
	// disallows any value of type T to be moved
	@disable operator[move];
}

Properties

Properties behave similar to regular fields, but are backed by getter and/or a setter methods. Depending on the existence and attributes of the defined accessors, a property can be read-only, read/write or write-only:

Declaring a property can be done using the regular syntax where get and set are used within curly braces to define the corresponding methods, or using the shortcut syntax where the lambda syntax => is used to define a single getter. In the latter case, the => can be prefixed by a ref attribute to signal that the value is returned by reference.

If the property has no explicit type, it will be inferred from the getter. A setter-only property must define an explicit type.

Example

struct Widget {
	private {
		var _width: int;
		var _height: int;
		var _caption: string;
	}

	// read-only
	var width { get => _width; }

	// shortcut syntax
	var height => _height;

	// read-write
	var caption {
		get => _caption;
		set(v) { _caption = v; redraw(); }
	}

	function redraw() {
		// ...
	}
}

Operating on Properties

Using modifying operators, such as assignment or increment operators, on a property will automatically generate code that uses the property getter and setter to implement the operation equivalent to operating on a plain value of the same type.

Example

struct MyArray {
	private {
		var _length: size_t;
		var _capacity: size_t;
		var _ptr: void*;
	}

	var length {
		get => _length;
		set(v) {
			if (v <= _capacity) {
				_length = v;
			} else {
				_ptr = realloc(_ptr, v);
				_length = _capacity = v;
			}
		}
	}
}

var arr: MyArray;

// normal setter call
arr.length = 10;

// modifying operator
arr.length += 5;
// translated to:
// [ref arr] { var tmp = arr.length; tmp += 5; arr.length = tmp; return tmp; } ()

Passing Properties as Arguments

Similarly to how operators are handled, passing a property to a ref or out parameter is translated to matching getter/setter calls internally.

Example

function foo(out num: size_t) { num = 42; }
function bar(ref num: size_t) { num++; }

var arr: MyArray;

// out parameter
bar(arr.length);
// translated to:
// var tmp: typeof(arr.length); bar(tmp); arr.length = tmp;

// ref parameter
foo(arr.length);
// translated to:
// var tmp = arr.length; foo(tmp); arr.length = tmp;