THT is in early Beta. We welcome contributors & feedback.

Classes & Objects

Work in Progress 

THT currently has a minimal approach to object-oriented programming.

We intend to support most of PHP's object-oriented functionality in future versions.

Shortcuts 

This tutorial uses the shortcuts for function (F) and this (@).

These are for readability only. They are one-to-one replacements and have no impact on performance.

Creating Objects 

Classes are defined within module files.

New objects for the class are created with the new command.

Fields are directly assigned to @ (shortcut for this) within the constructor (new), which is called when the object is created.

// file: modules/MyClass.tht

class MyClass {

    F new(num) {
        @.number = num;
        @.color = 'red';
    }

}

// file: pages/home.tht

let object = new MyClass(123);

print(object.number);  //= 123
print(object.color);   //= 'red'

Private State 

In the current version of THT, all functions and fields are public (accessible from outside callers).

As a temporary solution, THT automatically adds a private state field to all classes, to which you can assign a Map.

// file: modules/Counter.tht

class Counter {

    F new {
        @.state = {
            count: 0
        };
    }

    F add {
        @.state.count += 1;
    }

    F getCount {
        return @.state.count;
    }

}

// file: pages/home.tht

let counter = new Counter();

counter.add();
counter.getCount(); //= 1

print(counter.state.count);
//= ✖ ERROR: state is private

Private Naming (optional) 

You may also use the convention of prepending 'x' to your method and field names (e.g. xMyFunction) to signal that they should be considered private.

This is simply a naming convention — it does not impact accessiblity.

Composition 

The extends keyword isn’t yet supported.

However, instead of inheritance, you can use composition to re-use code across classes.

Composition is the technique of containing other objects within your object. You can then send method calls to these inner helpers as needed.

TipIt is considered a good practice to prefer composition instead of inheritance. Composition lets you include the functionality you need, without locking yourself into a strict heirarchy.

class User {

    F new(userId) {
        // An inner object
        @.logger = new Logger();

        @.userId = userId;
    }

    F log(message) {
        // Calling the inner object
        @.logger.log(@.userId ~ ': ' ~ message);
    }

    F login() {
        @.log('Logged in');
    }
}

Static Methods & Fields 

Because each class is contained within a module, you can use module-level scope to implement static functionality.

For static methods, simply define functions within the same module, outside of the class.

For static fields, you can assign data directly to the module.

// file: modules/MyClass.tht

// Module-level variable
MyClass.xNumObjects = 0;

F numObjects {
    return MyClass.xNumObjects;
}

class MyClass {

    F new {
        MyClass.xNumObjects += 1;
    }
}


// file: pages/home.tht

let object1 = new MyClass();
let object2 = new MyClass();

print(MyClass.numObjects());  //= 2

Meta-Methods 

All objects inherit special methods for dynamically handling fields and methods.

See Object.