-
Notifications
You must be signed in to change notification settings - Fork 3
Classes and OOP
Hassium allows you to declare your own classes as well as your own functions. Classes are objects that can have functions, properties, traits, and other classes declared inside them, as well as have object attributes.
The first type of classes we will be looking at are static classes. Static meaning that you are directly calling attributes of the class. The syntax of a class is the following: class <name> [: inherit1, inherit2, ... ] { <body> }
Throughout this section we will be creating a calculator class, start by opening a new file and typing the following:
class Calculator {
}
This declares a new class called Calculator
, with nothing inside it. Let's start by adding a function for adding:
class Calculator {
func add (x : int, y : int) : int {
return x + y;
}
}
Now if we wish to call the add
method from main
, we can simply do:
func main () {
println (Calculator.add (4, 6));
}
The .
is the attribute access operator, and it looks inside the Calculator
class (which is an object), and looks for an attribute called add
. When it finds it, it then invokes it with the arguments 4 and 6. Now let's go ahead and populate the rest of this class (I've taken out the newlines for readability):
class Calculator {
func add (x : int, y : int) : int { return x + y; }
func sub (x : int, y : int) : int { return x - y; }
func mul (x : int, y : int) : int { return x * y; }
func div (x : int, y : int) { return x / y; }
}
From main
or anywhere else that has access to the Calculator
class, these four methods can be called.
Creating an instance of a class is a basic tenant of Object Oriented Programming (OOP). When you create an instance (or instantiate) a class, you are creating a new object that has all the attributes of the parent object and is of type of the parent object. You can instantiate a class by invoking the class, returning back the new objectified class and executing the constructor, a method called before the new object is returned.
The constructor is a function called new
. Let's revisit the Calculator concept again, but this time create an object that takes in two numbers in the constructor and preforms operations on them. First we need to add our constructor that accepts two numbers:
class Calculator {
func new (x : int, y : int) {
this.x = x;
this.y = y;
}
}
You will instantiate this in the main method by doing the following:
func main () {
calc = new Calculator (4, 7);
}
The new
keyword is used to invoke the class, but is redundant an optional. 4 and 7 are passed in as arguments to the constructor, which assigns them to values in this
. this
is a self-reference, or a way to access the instance of a class. If I were to instantiate multiple copies of calc
, this
would mean something different in each one.
Now we can re-add in our methods from the calculator class, but that use the values provided by the constructor:
class Calculator {
func new (x : int, y : int) {
this.x = x;
this.y = y;
}
func add () : int { return this.x + this.y; }
func sub () : int { return this.x - this.y; }
func mul () : int { return this.x * this.y; }
func div () { return this.x / this.y; }
}
Now we can start calling these methods in an object oriented manner:
func main () {
calc1 = new Calculator (4, 5);
calc2 = new Calculator (7, 15);
println (calc1.add ()); # prints 9
println (calc1.sub ()); # prints -1
println (calc2.mul ()); # prints 105
println (calc2.div ()); # prints 0.46666
}
A class can extend and inherit the attributes from another class. A class can inherit from an infinite amount of other classes. This is useful for a class that contains some basic attributes, but you wish to expand on to add more advanced attributes.
Let's create a class Dog
. This class should take in a name and weight, as well as contain a few basic methods like barking.
class Dog {
func new (name : string, weight : int) {
this.name = name;
this.weight = weight;
}
func speak () {
println ("Bark!");
}
}
This is all well and nice, but say you wanted to create a class specifically to represent a big dog. This class still needs the name and weight, but it should also have a method for retrieve, and it should bark extra loud. Since our Dog
class already has a constructor that does what we need for the BigDog
class, we can simply have the BigDog
class inherit it.
class BigDog : Dog {
}
Now the class BigDog
is a copy of the Dog
class, it's constructor and speak
function imported over. We can add in the method called retrieve now:
class BigDog : Dog {
func retrieve () {
println ("Here's the ball!");
}
}
This is almost complete, but remember we said that for the BigDog
class we wanted the speak method to behave differently. To do this we will make use of something called overriding, where if the class that is doign the inheriting (in this case BigDog
), any methods it has that are of the same name as the methods of the base class override those of the base class. Simply put, we just need to write a function called speak
in BigDog
to take care of this.
class BigDog : Dog {
func retrieve () {
println ("Here's the ball!");
}
func speak () {
println ("GROWL, GROWL. BARK BARK!");
}
}
Now you have a class that inherits a constructor from a base class, has it's own unique methods, and overrides a method from the base class.
Sometimes a class can have members which do not need to (or should not) be accessed from outside the class declaration. These members are prefixed with the priv
keyword. Let's start with looking at a private function inside a class:
func main () {
c = new MyClass ();
c.publicFunc ();
c.privateFunc (); # Throws an exception since privateFunc is private.
}
class MyClass {
func new () {}
func publicFunc () {
println ("This is a public func!");
this.privateFunc (); # Fine since calling a private func from inside the class it was declared.
}
priv func privateFunc () {
println ("This is a private func!");
}
}
The first call is to c.publicFunc ()
, which displays a message, then calls privateFunc ()
, which is valid because it is being called from inside the declaring class. The second call from main ()
is directly to privateFunc ()
, which is invalid and throws an exception saying that privateFunc ()
is private.