Users › 06 Interfaces and polymorphism
Interfaces are how Lopolith does abstraction. There is no
Object root type, so every polymorphic value has a precise static
type.
An interface is its own file, like any other type:
%interface com.example.todo.TaskSink
void add(String title)
int size()
Interfaces may also declare fields and methods with default bodies:
%interface com.example.Shape
int id
int area()
int areaTwice() {
return this.area() * 2
}
A default body may read interface fields and call interface methods; those calls dispatch to the implementing class at runtime.
Every interface member must be bound explicitly with
Interface@member. The member name may differ from the interface's —
only the signature has to match.
%class com.example.todo.TaskList implements TaskSink
#import com.example.todo.TaskSink
int _count
void add(String title) TaskSink@add {
...
}
int size() TaskSink@size {
return this._count
}
pub;
methods are automatically public.pub int id NamedIface@identifier,
as long as the types match exactly.int area() Shape@area, Drawable@area { ... } — all bound
signatures must agree.void ___init(int mode)) as an instantiation contract; every
implementing class must provide them. Constructors are not virtual.&I&Shape is the class that implements an interface, not
an instance. Tokens let you pass a class around and instantiate it later:
void start(&Activity cls) {
Activity a = new cls() // instantiate from the token
}
start(&MainActivity) // pass a class token
new token(...) must be a simple variable.== / != are defined on tokens (same class);
=== and comparisons against instances are compile errors.Because there is no Object, a reference is only assignable to its
own class, an interface it implements, or null. Casting an interface
back to a class is rejected at compile time — the runtime performs no type
checks, so the language simply does not allow it.
The built-in Exception interface is an ordinary interface with
default methods. A custom exception is just a class that implements it and binds
the three members:
%simple com.example.ifaces.Demo implements Main
#import Std
int run(int argc, String[] argv) Main@run {
try {
throw new $MyError("boom", 42)
} catch (Exception e) {
Std.print("caught: ", e.toString(), " code=", e.toInt(), "\n")
}
return 0
}
%sub MyError implements Exception
String msg
int code
void ___init(String msg, int code) {
this.msg = msg
this.code = code
}
String getName() Exception@getName {
return "MyError"
}
String toString() Exception@toString {
return "MyError: " + this.msg
}
int toInt() Exception@toInt {
return this.code
}
caught: MyError: boom code=42
The task-list example uses a real interface (TaskSink) with two
implementations in the same class.