Perhaps Ferret's most unique feature is its ISA inheritance system. The name
ISA is borrowed from Perl, where package variables @ISA
consist of parent
package names. However, Ferret's inheritance system is quite different.
Ferret objects do not inherit from classes; they inherit from other objects. As silly as it may sound, objects can belong to any number of classes. But they don't inherit from those classes; they inherit from their prototype objects.
If an object is an instance of the String class, for instance, its *ISA
(list of parent objects) would include the String.proto
object.
Below is an example of a Ferret class from the standard library.
package Math
class Point
init {
need @x: Num, @y: Num
}
.distanceTo {
need $pt2: Point
$dx = @x - $pt2.x
$dy = @y - $pt2.y
-> sqrt($dx ^ 2 + $dy ^ 2)
}
.distanceFromOrigin
-> @distanceTo(*class(0, 0))
.pretty -> "(@x, @y)"
.toString -> @pretty
.description -> "Point" + @pretty
func midpoint {
need $pt1: Point, $pt2: Point
-> *class(
x: ($pt1.x + $pt2.x) / 2,
y: ($pt1.y + $pt2.y) / 2
)
}
func distanceBetween {
need $pt1: Point, $pt2: Point
-> $pt1.distanceTo($pt2)
}
Initializing an object as a certain type is as simple as adding an object to
its *ISA
list. However, this is not typically done directly. Consider this
example.
# Create an empty object. This is like {} in JavaScript.
$obj = (:)
# Make the object an instance of Point.
Math::Point.init($obj)(0, 0)
# The object is now a Point representing the origin.
# Therefore, $obj.*ISA includes Math::Point.proto.
inspect($obj)
Output
[ Point ](
x = 0
y = 0
)
This is equivalent to below, as calling a class creates an empty object and initializes it in one step.
$obj = Math::Point(0, 0)
Because Ferret objects can inherit from any objects, a class is not required for inheritance. Below is an example of basic inheritance without a class.
# create a basic object representing a male being.
$male = (gender: "male")
# create a basic object representing a specific person.
$person = (name: "Jake", age: 22)
# add $male to $person's *ISA list
$person.*ISA.push($male)
inspect($person)
Output
[ Object ](
age = 22
name = "Jake"
(gender) = "male"
)