Classes define user-created object types. A class contains constructor code, fields, and methods.
User-defined objects behave like other Expr objects: they can be stored in variables, passed to functions, returned from functions, used as callback owners, and accessed with method/property syntax.
A class is declared with `class`, a name, a parameter list, and a body.
class ToolInfo(number, diameter) { Number = number; Diameter = diameter; function Radius() { return Diameter / 2; } }
The class name becomes a constructor in the current session.
tool = ToolInfo(3, 6.0); print(tool.Number); // 3 print(tool.Radius()); // 3
Class declarations are top-level declarations. They are not allowed inside `if`, `while`, `for`, or other statement blocks.
The class body is also the constructor body.
When an object is created, Expr runs the non-function statements in the class body once for that new object.
class ProbeResult(x, y, z) { X = x; Y = y; Z = z; HasError = false; } result = ProbeResult(10, 20, -1);
Assignments in the constructor create object fields.
Function declarations inside the class body do not run during construction. They define methods.
Class constructor parameters are positional.
class Point(x, y) { X = x; Y = y; } p = Point(10, 20);
The argument count must match the parameter count. Default arguments and keyword arguments are not supported.
Point(10); // error Point(10, 20, 30); // error
Use empty parentheses when a class has no parameters:
class Counter() { Value = 0; } c = Counter();
Fields are per-object values.
Inside a constructor or method, plain assignment can create or update a field:
class Counter(start) { Value = start; function Inc() { Value = Value + 1; return Value; } }
Fields can be read with property syntax:
c = Counter(5); print(c.Value); // 5
Inside a method, `this.field` explicitly reads a field from the current object:
class Counter(start) { Value = start; function Read() { return this.Value; } }
Direct property assignment is not supported:
c.Value = 10; // error this.Value = 10; // error
To change a field from inside a constructor or method, assign the bare field name.
`set` creates a local variable. It does not create or update an object field.
class Counter(start) { Value = start; function Test() { set Value = 100; return this.Value; // still the object field } }
Use `this.field` when a local variable or parameter has the same name as a field.
class ToolInfo(number) { Number = number; function SetNumber(number) { Number = number; return this.Number; } }
Compound assignment can update an object field when the target resolves to that field:
class Counter() { Value = 0; function Inc() { Value += 1; return Value; } }
Compound assignment through property syntax is not supported:
this.Value += 1; // error
Methods are declared with `function` inside the class body.
class Accumulator() { Total = 0; function Add(value) { Total += value; return Total; } } acc = Accumulator(); acc.Add(10); acc.Add(5);
A method call uses the same syntax as built-in object method calls:
object.Method(arguments);
Methods can return any Expr value. Returning `this` is useful for chaining:
class Builder() { Text = ''; function Add(text) { Text += text; return this; } function Get() { return Text; } } s = Builder().Add('A').Add('B').Get();
Method overloading by argument count is not supported for user-defined class methods. Use different method names.
`this` is available inside class constructor code and class methods.
Use `this` to:
class Counter(start) { Value = start; function Add(value) { Value += value; return this.Value; } function AddTwice(value) { return this.Add(value) + this.Add(value); } }
Inside a method, a bare function-style call can resolve to a method on `this` before falling back to session functions and built-in functions.
class Counter(start) { Value = start; function Add(value) { Value += value; return Value; } function AddTwice(value) { return Add(value) + Add(value); } }
Use `this.Add(value)` when you want the method call to be explicit.
A method can be referenced without calling it.
class DialogScript() { Count = 0; function OnClick() { Count += 1; } function Show() { btn = textbutton().text('Run').on_click(this.OnClick); window().title('Demo').size(200, 100).add(btn).show(); } } script = DialogScript(); script.Show();
`this.OnClick` is a method reference. It can be passed to APIs that expect a callback.
A method reference is an object value. It can also be called explicitly with `call(…)`.
callback = script.OnClick; callback.call();
Callback argument rules depend on the object or host API that invokes the callback.
Class names can use namespaces.
class Math::Accumulator() { Total = 0; function Add(value) { Total += value; return Total; } } acc = Math::Accumulator(); acc.Add(5);
Namespaced includes can also place included class definitions into a namespace. See Include system.
When a call name can refer to both a class constructor and a function, Expr resolves the class constructor first.
function Box() { return 'function'; } class Box() { Value = 'class'; } b = Box(); // creates a Box object
Re-defining a class name in the same session replaces the previous class definition.
User-defined classes belong to the active Expr session.
A class defined in one named session is not visible in another named session unless it is defined there too.
class Box(value) { Value = value; } b = Box(7);
Use the global `session` object to inspect current session classes:
print(session.list_classes());
See session and Execution model and sessions.
Object variables hold object references.
class Person() { Name = ''; function SetName(name) { Name = name; } } p1 = Person(); p1.SetName('A'); p2 = p1; p2.SetName('B'); print(p1.Name); // B
Use `clone()` when you need an independent copy.
p3 = p1.clone(); p3.SetName('C');
User-defined objects are cloneable when their field values are cloneable. If the object graph contains a non-cloneable object, `clone()` raises an error.
Expr classes currently do not support:
Previous: snake
Next: Include system