The syntax for a class definition is
class ClassName(Super1, Super2, ...)
... Field definitions...
end
Declaring a class causes a read-only global variable having the name of the class to be included in the program, just like for a procedure or a record. The variable will have a value of type class
, representing the class itself. Classes cannot be created or changed dynamically; they are hardwired into the icode file.
The lang.Class
class contains many static methods which allow the inner structure of a class to be examined at runtime.
A class can have zero, one or several superclasses, from which it inherits fields. Full details of how Object Icon implements inheritance can be found here.
The field definitions are either variables or methods. Each definition starts with the access modifiers, which specify who may access the field, and how it may be accessed. Typical variable declarations are :-
private x, y # Private instance variables
public static const PI # A constant, accessible anywhere
private readable z # A private variable, but accessible read-only from outside
The meaning of the various modifiers is explained in detail here.
A method definition looks like :-
# A public instance method
public set_loc(x, y)
self.x := x
self.y := y
end
# A static method accessible without an instance
public static origin()
return Point(0,0)
end
To bring these things together, here is a simple class definition to represent an x,y point :-
import util(Math)
class Point()
public const x, y
public static const ORIGIN
private static init()
ORIGIN := Point(0, 0)
end
# Radius of a circle on which this point lies
public radius()
return Math.sqrt(x * x + y * y)
end
# Distance between two points
public static distance(p1, p2)
return Math.sqrt((p1.x - p2.x) ^ 2 + (p1.y - p2.y) ^ 2)
end
public new(x, y)
self.x := x
self.y := y
return
end
end
The static init() method is used to initialize any static variables. It is called automatically the first time the class is referenced. The new() method is similar, but is used to initialize instances - it is called automatically every time a new object is created. Some examples of using the class :-
p1 := Point(-2, -3)
p2 := Point(4, 3)
write(Point.distance(p1, p2))
write(p2.radius())
write(Point.distance(p2, Point.ORIGIN))
One thing to note about the Point
class is that it is immutable. That means that its state does not change once it has been created. This is achieved by declaring its two instance variables as const. The following attempts to change these variables’ values would cause a runtime error :-
p1.x := 100
Point.ORIGIN.y := 1
p1.new(3, 4)
The static field ORIGIN
is also declared const
. That means that any attempt to change its value would also cause a runtime error :-
Point.ORIGIN := 1 # Run-time error
Naturally these const variables have to be assignable at some point in order to be initialized. For static variables, they are assignable during class initialization (when the init
method is called), and for instance variables during object initialization (when the new
method is called). Thereafter, the variables become “locked”, and are no longer assignable.