Classes & Interfaces
Serez Code has C#-style OOP — interfaces for pure data shapes, classes for data + behavior, and single inheritance with super().
Interfaces
An interface is a typed data record — fields only, no methods. Think of it as a strict struct:
interface Point {
x: decimal,
y: decimal,
}
let origin = new Point({ x: 0.0, y: 0.0 })
let p = new Point({ x: 3.0, y: 4.0 })
out p.x // → 3.0
p.x = 10.0
out p.x // → 10.0Classes
Classes bundle data and behavior. The constructor has the same name as the class and is marked public:
public class Animal {
public Animal(string name, string sound) {
this.name = name
this.sound = sound
this.energy = 100
}
public void speak() {
out "{this.name} says: {this.sound}"
}
public void eat(int amount) {
this.energy = this.energy + amount
}
public string describe() {
return "{this.name} (energy: {this.energy})"
}
}
let dog = new Animal("Rex", "Woof")
dog.speak() // → Rex says: Woof
dog.eat(20)
out dog.describe() // → Rex (energy: 120)Inheritance
Use : ParentClass to inherit. Call super(...) first to pass arguments up to the parent constructor:
public class Dog : Animal {
public Dog(string name, string breed) {
super(name, "Woof") // runs Animal's constructor
this.breed = breed
}
public string getBreed() {
return this.breed
}
// Override the parent method
public string describe() {
return "{this.name} [{this.breed}] (energy: {this.energy})"
}
}
let fido = new Dog("Fido", "Labrador")
fido.speak() // → Fido says: Woof (inherited from Animal)
out fido.describe() // → Fido [Labrador] (energy: 100)
out fido.getBreed() // → Labradorsuper(...) yourself when the parent needs arguments, as Dog does above.public class Base {
public Base() { this.n = 10 }
}
public class Child : Base { } // no constructor at all
out (new Child()).n // → 10 — Base() ran on its own
public class Other : Base {
public Other() { this.own = 5 } // no super() call
}
let o = new Other()
out o.n // → 10 — inherited anyway
out o.own // → 5Public & private methods
public class Counter {
public Counter(int start) {
this.value = start
}
private void increment() {
this.value = this.value + 1
}
public int next() {
this.increment() // private method — ok from inside
return this.value
}
}
let c = new Counter(0)
out c.next() // → 1
out c.next() // → 2
// c.increment() ❌ ERROR: cannot call private method from outsideStatic methods
Static methods belong to the class itself, not to any instance. No this available:
class MathUtils {
public static int square(int n) { return n * n }
public static int max(int a, int b) {
if (a > b) { return a }
return b
}
}
out MathUtils.square(5) // → 25
out MathUtils.max(7, 3) // → 7Getters & setters
Computed properties that look like regular fields from the outside:
public class Temperature {
public Temperature(decimal celsius) {
this.celsius = celsius
}
public get decimal fahrenheit() {
return this.celsius * 9.0 / 5.0 + 32.0
}
public set fahrenheit(decimal f) {
this.celsius = (f - 32.0) * 5.0 / 9.0
}
}
let t = new Temperature(0.0)
out t.fahrenheit // → 32.0 (getter, no parentheses)
t.fahrenheit = 212.0 // setter
out t.celsius // → 100.0Method references
Writing obj.method without parentheses gives you the method as a value, bound to that object — it does not call it. Call it later and it still mutates the object it came from. This is what makes it possible to hand a handler around as data: store it in an array or a dictionary, pass it to another function, or give it to a UI component as a callback prop.
public class Counter {
public Counter() { this.n = 0 }
public void incr() { this.n = this.n + 1 }
public void add(int k) { this.n = this.n + k }
}
let c = new Counter()
let bump = c.incr // no parentheses: a reference, NOT a call
out c.n // → 0 (nothing ran)
bump()
bump()
out c.n // → 2 (mutates the original object)
let handlers = [c.incr, c.add]
handlers[1](10)
out c.n // → 12Resolution for a parenthesis-less obj.name is: a field first, then a getter (get name(), which does run on read), and only then a method reference. A bound reference keeps its class context, so its body can still reach the class's own private members — and referencing a private method from outside is rejected just like calling it would be.
<TaskRow onPick={this.pick} /> // parent: a reference, not a call
<Button onClick={this.props.onPick}>…</Button> // child: invokes it on clickAbstract classes
Abstract classes can't be instantiated directly — they define a contract for subclasses:
abstract class Shape {
public Shape(string name) {
this.name = name
}
// Subclasses must implement this
public decimal area() {
throw "area() not implemented in {this.name}"
return 0.0
}
public string describe() {
return "{this.name}: area={this.area()}"
}
}
public class Circle : Shape {
public Circle(decimal r) {
super("Circle")
this.r = r
}
public decimal area() { return 3.14159 * this.r * this.r }
}
let c = new Circle(5.0)
out c.describe() // → Circle: area=78.53975Sealed classes
A sealed class can't be subclassed — useful for value types you want to lock down:
sealed class Token {
public Token(string kind, string value) {
this.kind = kind
this.value = value
}
}
// public class MyToken : Token { } ❌ ERROR: Cannot inherit from sealed class 'Token'Enums
enum Direction { North, South, East, West }
enum Status { Ok, Error, Pending }
let dir = Direction.North
out dir // → North
if (dir == Direction.North) {
out "Heading north!"
}
fn string describe(any s) {
switch (s) {
case Status.Ok: { return "All good" }
case Status.Error: { return "Something failed" }
case Status.Pending: { return "Still waiting" }
default: { return "Unknown" }
}
}
out describe(Status.Ok) // → All good