thp-lang.org/md/learn/index.md

3.9 KiB

Accurate visual description of THP

Welcome

Welcome to the documentation of the THP programming languague.

THP is a new programming language that compiles to PHP.


This page discusses some of the design decitions of the language, if you want to install THP go to the installation guide

If you want to learn the language, go to the learn section.

Goals

  • Bring static typing to PHP: Not just type hints, not use mixed for everything that isn't a primitive type.
  • Avoid automatic type conversion.
  • Remove the inconsistencies in the language.
  • Organize the stdlib.
  • Differentiate between Arrays, Tuples, Maps and Sets.
  • Create a consistent language.
  • Create typings for popular libraries (like TS's .d.ts).
  • Have a simple instalation and configuration (requiring just Composer).
  • Ship a fast, native binary (written in Rust) (why use PHP when we can go native?).
  • Sub 10ms watch mode.
  • Support in-place compilation.
  • Emit readable PHP code.
  • Implement a LSP server.

Not goals

These are not aspects that THP looks to solve or implement.

  • Be what TypeScript is for JavaScript (PHP with types).
  • Use PHP syntax/conventions.
  • Be familiar for PHP developers.

Philosophy

  • Consistency over familiarity
  • Change over conventions
  • Explicit over implicit

Some differences with PHP

// PHP
$has_key = str_contains($haystack, 'needle');

// THP
val has_key = haystack.contains("needle")
  • Explicit variable declaration
  • No $ for variable names (and thus no $$variable)
  • No semicolons
  • Use methods on common datatypes
  • Strings use only double quotes

// PHP
[
    'names' => ['Toni', 'Stark'],
    'age' => 33,
    'numbers' => [32, 64, 128]
]

// THP
Obj {
    names: #("Toni", "Stark"), // Tuple
    age: 33,
    numbers: [32, 64, 128]
}
  • Tuples, Arrays, Sets, Maps are clearly different
  • JS-like object syntax

// PHP
$cat = new Cat("Michifu", 7);
$cat->meow();

// THP
val cat = Cat("Michifu", 7)
cat.meow();
  • No new for classes
  • Use dot . instead of arrow -> syntax

// PHP
use \Some\Deeply\Nested\Class
use \Some\Deeply\Nested\Interface

// THP
use Some::Deeply::Nested::{Class, Interface}
  • Different module syntax
  • PSR-4 required
  • No include or require

Other things:

  • Pattern matching
  • ADTs

Runtime changes

THP should add as little runtime as possible.

// ===== current =======
val name = "John"
var name = "John"

String name = "John"
var String name = "John"



// ===== new? =======
let name = "John"
let mut name = "John"

String name = "John"
mut String name = "John"


// For primitive datatypes (Int, Float, Bool, String?)

// Cloned
fun add(Int x)
// Still cloned, but the x **binding** can be mutated, not the original variable
fun add(mut Int x)
// Same as 1st
fun add(clone Int x)


// For other datatypes

// Pass an immutable reference
fun add(Obj o)
// Pass a mutable reference
fun add(mut Obj o)
// Clone the argument
fun add(clone Obj o)


// Only references are passed, not "variables" (as PHP calls them)
let john = Obj {name: "John"}
/*
    john --------> {name: "John"}
*/

fun set_empty(mut Obj person) {
    /*
        john ------┬-->  {name: "John"}
        person ----┘ 
    */

    // This creates a **new** Obj, and the variable `person` now points to it.
    person = Obj {name: "Alex"}
    /*
        john --------->  {name: "John"}
        person ------->  {name: "Alex"}
    */
}

set_empty(mut obj)

print(obj)  // Obj {name: "John"}

Example

use PDO
use Globals::Env

val (Some(dbUri) Some(dbUser) Some(dbPassword)) = (
    Env::get("DB_URI")
    Env::get("DB_USERNAME")
    Env::get("DB_PASSWORD")
)
else {
    die("All 3 db environment variables must be set.")
}

match PDO(dbUri dbUser dbPassword)
| Ok(connection) { /* db operations */ }
| Err(pdoException) { /* handle exception */ }