Your own types, 4 of 8
Inheritance
Extend a Class, override its Methods, call the original with Super, and test an object's Class.
What you’ll build
A program that keeps circles, rectangles, and squares in one list of shapes, and asks each for its area. Each shape works its area out its own way, while the code that uses them treats them all as Shapes.
Extending a Class
Class Circle Extends Shape makes Circle a kind of Shape: it has Shape’s fields and Methods,
and adds its own. Its New calls Super.New(...), the New of the Class it extends, to set up
the Shape part. An Abstract Class can’t be made itself; it exists to be extended, and its
Abstract Methods are ones each Class extending it must give.
Import std.core
Abstract Class Shape
ReadOnly Field Name: String
New(name: String)
Name = name
End New
Abstract Method Area(): Float
Method Describe(): String => "{Name} with area {Area():.2}"
End Class
Class Rectangle Extends Shape
Field width: Float
Field height: Float
New(width: Float, height: Float)
Super.New("rectangle")
Self.width = width
Self.height = height
End New
Override Method Area(): Float => width * height
End Class
Local box = Rectangle(2.0, 3.0)
Print(box.Describe())rectangle with area 6.00
Override is required on a Method that replaces one the Class inherits, so replacing a Method is
never an accident.
One list, many Classes
An object of a Class converts to any Class it extends, so a Shape[] holds circles and
rectangles alike. A call to a Method runs the version of the object’s own Class: Describe, which
Shape wrote, calls whichever Area the object has.
Import std.core
Import std.math
Abstract Class Shape
ReadOnly Field Name: String
New(name: String)
Name = name
End New
Abstract Method Area(): Float
Method Describe(): String => "{Name} with area {Area():.2}"
End Class
Class Circle Extends Shape
Field radius: Float
New(radius: Float)
Super.New("circle")
Self.radius = radius
End New
Override Method Area(): Float => Pi * radius * radius
End Class
Class Rectangle Extends Shape
Field width: Float
Field height: Float
New(width: Float, height: Float, name: String = "rectangle")
Super.New(name)
Self.width = width
Self.height = height
End New
Override Method Area(): Float => width * height
End Class
Local shapes: Shape[] = [Circle(1.0), Rectangle(2.0, 3.0), Circle(0.5)]
Local total: Float = 0.0
For shape In shapes
Print(shape.Describe())
total += shape.Area()
End For
Print("total area {total:.2}")circle with area 3.14 rectangle with area 6.00 circle with area 0.79 total area 9.93
Pi is a constant from std.math.
Super
Inside an override, Super.Method() calls the version of the Class extended, so an override can
add to it instead of starting over. Here Square extends Rectangle and adds to its
Describe.
Import std.core
Class Rectangle
Field width: Float
Field height: Float
New(width: Float, height: Float)
Self.width = width
Self.height = height
End New
Method Area(): Float => width * height
Method Describe(): String => "{width} by {height}, area {Area()}"
End Class
Class Square Extends Rectangle
New(side: Float)
Super.New(side, side)
End New
Override Method Describe(): String => "a square, " + Super.Describe()
End Class
Local shapes: Rectangle[] = [Rectangle(2.0, 3.0), Square(4.0)]
For shape In shapes
Print(shape.Describe())
End For2 by 3, area 6 a square, 4 by 4, area 16
A Final Method can’t be overridden, and a Final Class can’t be extended.
Asking an object’s Class
x Is T tells whether an object is of Class T, or of one extending it. x As? T gives the
object as a T, or Null when it isn’t one, and Select with Case name As T picks a case by
Class. x As T converts without asking, and panics when the object isn’t a T.
Import std.core
Class Shape
End Class
Class Circle Extends Shape
Field Radius: Float = 1.0
End Class
Class Rectangle Extends Shape
End Class
Class Square Extends Rectangle
End Class
Local shapes: Shape[] = [Circle(), Rectangle(), Square()]
For shape In shapes
Local circle = shape As? Circle
If circle != Null Then Print("a circle of radius {circle.Radius}")
If shape Is Rectangle Then Print("a rectangle, or a kind of one")
Select shape
Case square As Square
Print(" exactly: a square")
Case rectangle As Rectangle
Print(" exactly: a rectangle")
Default
Print(" exactly: neither")
End Select
End Fora circle of radius 1 exactly: neither a rectangle, or a kind of one exactly: a rectangle a rectangle, or a kind of one exactly: a square
The Case for Square comes before the one for Rectangle, since a Square is a Rectangle too:
the other way round, the Square case could never match, and fb says so.
What you learned
Extendsmakes a Class a kind of another, with its fields and Methods.Super.New(...)runs the extended Class’s constructor, andSuper.M()its Method.Overridereplaces an inherited Method; calls run the object’s own Class’s version.- An
Abstract Classcan’t be made, and eachAbstract Methodmust be overridden. Is,As?,As, andCase x As Ttest and convert an object’s Class.
The rules are in the language reference.
Report an issue with this page or with FutureBlitz on GitHub.