A modern, type safe, secure language compiled to PHP

Inspired by Rust, Zig and Kotlin, THP has a modern syntax, semantics, type system and stdlib.

union Animal {
    Dog(String),
    Cat(String, Int),
}

val my_pet = try Pets::get_first()

match my_pet
case Dog(name)
{ 
    print("{name} has 1 live ")
}
case Cat(name, lives)
{
    print("{name} has {lives}")
}

Generics & Types

Type safety is enforced at compile time. Everything has a specific type. There is no `mixed`.

You can use generics where neccesary.
Array[Int] numbers = [0, 1, 2, 3, 4, 5]

numbers.push("7")  // Compile error: expected an Int, found a String

// Runtime type checking
val object = try JSON::decode(data)
val name = try object.get[String]("name")

// Any is available, but it's not usable without an explicit cast
fun mock() -> Any { ... }

// Compile error: Cannot use `Any` without an explicit cast
val result = mock()
// Ok
val result = mock() as Stringthp
    

Tagged unions

Make invalid state irrepresentable.
Model data in a type-safe way.
Ensure all cases are handled.
union DirEntry {
    File(String),
    Dir(String),
}

val root = DirEntry::Dir("/")
val test_file = DirEntry::File("test.txt")thp
    

Pattern matching

Match on values, tuples, enums, unions, types etc.
Guards available!
match test_file
case DirEntry::File(filename)
    if !filename.starts_with(".")
{
    print(filename)
}
case _
{
    print("A valid file was not found")
}thp
    

Null safety

Nulls are explicit and require handling. Types can be nullable, and they must be checked before usage.
The stdlib makes extensive use of them.
String? username = Post::get("username")

if username?
{
    // username is a `String` here
    print("Hello, {username}")
}thp
    

Errors as values

Exceptions are values and don't disrupt control flow.

Errors cannot be ignored, and we have syntax sugar to ease them.
val user_id = POST::get("id")
val user = try User::find(user_id)
catch DBException e
{
    log_error(e.message)
    return page(.{}, 404)
}thp