Classes and Inheritance
Source: Dev.to
We now move on to complete the interpreter by adding support for classes.
Classes can inherit from other classes (re‑using their properties and methods) while also allowing customisation through modifications and additions.

What I built
Commits bac3f3c, bfa82b9, 03b3af3, 6c70087
What I understood
-
Class Declarations
- The parser creates a
Stmt.Classnode for each class declaration, containing the class name and its list of methods. - The resolver declares the class name in the current scope so the class can refer to itself (e.g., for recursion).
- When the interpreter visits
Stmt.Class, it turns the AST node into aLoxClassobject that stores a map of methods (each converted into aLoxFunction).
- The parser creates a
-
Class Instances / Objects
- Lox doesn’t use a
newkeyword. LoxClassimplements theLoxCallableinterface, so a class is instantiated whenever it is called.- Calling a class creates a new
LoxInstanceand returns it. - The instance keeps a reference to its class (
LoxClass) so it can later look up methods.
- Lox doesn’t use a
-
Properties
- Fields aren’t declared in the class; they are created on assignment through instances.
- When the interpreter evaluates an object that is a
LoxInstance, it first callsget(), which checks the instance’s field map. - If the field exists, its value is returned; otherwise the interpreter looks for a method. If neither is found, a runtime error is thrown.
- The parser cannot distinguish a set from a get expression until it sees an
=sign. It therefore parses the left‑hand side as a regular expression (get) and, on encountering=, converts that node into asetnode. - When
set()is invoked, thefieldsmap is updated (overwriting any existing key).
-
Methods
- Lox methods don’t have the
funkeyword and are accessed through instances. - If a method is extracted (e.g., assigned to a variable) and called later,
thismust still refer to the instance from which the method was extracted. - To achieve this, when a method is accessed,
LoxClasscallsbind(instance)on the underlyingLoxFunction. bind()creates a new environment nested inside the method’s original closure, definesthisin that environment, and returns a newLoxFunction.- If
thisis used outside a class, the resolver (which tracks whether we’re inside a class) reports an error; otherwise it resolvesthisas a normal local variable. - The interpreter looks up
thisin the environment like any other variable, and thanks to the binding step the correct instance is found.
- Lox methods don’t have the

-
Constructors
- User‑defined constructors are called
init. - When
LoxClass.callfinds aninitmethod, it invokes it immediately to set up the new instance. - The arity of the call is checked against the initializer’s parameter count.
initalways returnsthis(even if the user tries to return another value). The resolver enforces this by tracking anisInitialiserflag inLoxFunction.
- User‑defined constructors are called
-
Inheritance
- A subclass can inherit methods from a superclass via a reference stored in the subclass’s
LoxClass. Method lookup walks up the inheritance chain. - The parser now creates a
Stmt.Classnode that also contains asuperclassfield (anExpr.Variable). - The resolver checks for self‑inheritance and reports an error if detected.
- If a superclass exists, the resolver creates a new scope and defines
superin it, makingsuperavailable to all methods of the subclass. - While creating a subclass, the interpreter creates a new environment, defines
superto point to the superclass, and then creates the methods. - Method lookup proceeds by first checking the instance’s fields, then the class’s methods, and finally the superclass’s methods (if any). If the chain ends with
null, the lookup fails.
- A subclass can inherit methods from a superclass via a reference stored in the subclass’s

super- The
superkeyword lets subclasses override a method while still being able to call the original implementation from the parent class. - Even if a chain of subclasses overrides the same method,
superalways resolves to the correct immediate parent implementation.
- The
All the above reflects the current state of the Jlox interpreter after adding full class support, including inheritance, constructors, and the super keyword.
Class definition
- It is followed by a dot and an identifier (
super.method) and is parsed as anExpr.Supernode. - It looks up a method on the superclass but binds it to the current instance (
this), with both belonging to different environments. - The resolver treats
superas a local variable and calculates its distance (the number of hops) from the environment in whichsuperis defined.
What’s next:
Some extensions to Lox—support for lists and for‑in loops.
Musings
Blogging this project has been really good for me. Even though I’m working on other projects at the moment, trying to explain what I did (months ago!) forces me to recall the details and the reasoning behind them. In a way, the insights I gained earlier continue to influence how I approach my current work.
I absolutely love documenting what I do, even if it’s the most mundane activity. In Indian philosophy, work is among the highest acts of devotion. Whatever we do, if we do it with intent, it leads us to competence and mastery, because it’s the process of learning and doing that helps us become our best versions. Tagore put it well:
“Where tireless striving stretches its arms towards perfection…”
Where else will God lie but in that perfection? Hence, I remind myself of all that I’ve learned.
