It uses dynamic binding.
In Java it would look like something this (but it's less useful without proper closures):
abstract class Bool {
void ifTrue(Runnable f, Runnable g);
}
class True extends Bool {
void ifTrue(Function f, Function g) {
f.run();
}
}
class False extends Bool {
void ifTrue(Function f, Function g) {
g.run();
}
}
Then, given a variable Bool b;
the if-then-else becomes b.ifTrue(new Runnable() {
public void run() {
System.out.println("It's true!");
}
}
, new Runnable() {
public void run() {
System.out.println("Not true!");
}
}
);
It's a bit more verbose, though...