# A Tour of Morfa

## Basic usage of aggregate types

### Structs

``````import morfa.math.base: sqrt;

struct Complex
{
var re: float;
var im: float;

func magnitude(): float
{
return sqrt(re * re + im * im);
}

static func conjugate(c: Complex): Complex
{
return Complex(c.re, -c.im);
}
}
``````

`Complex` may be used as follows:

``````unittest
{
// Create a Complex and initialize its fields
var c = Complex(3.0, 4.0);
assert(c.re == 3.0);
assert(c.im == 4.0);

// Call a Complex's method
var mag = c.magnitude();
assert(mag == 5.0);
}
``````

The expression `Complex(3.0, 4.0)` is a struct literal. It's value is a `Complex` with the fields `re` and `im` initialized to `3.0` and `4.0`, respectively.

If you declare a `Complex` variable but do not provide an initializer, `re` and `im` will be initialized with default values for `float`:

``````import morfa.math.base;

unittest
{
var complexNaN: Complex;
assert(isNaN(complexNaN.re) and isNaN(complexNaN.im));
}
``````

Also note the `static` member of `Complex`. As in C++ or Java, static member functions of aggregate types are not associated with any object of the type.

``````unittest
{
var c = Complex(1.0, 2.0);
var c2 = Complex.conjugate(c);
assert(c2.re == c.re and c2.im == -c.im);
}
``````

Values of struct types are similar to values of primitive types like `int` and `float` in that they are passed to—and returned from—functions by value. Consider the following definition of `+`:

``````func + (a: Complex, b: Complex): Complex
{
a.re += b.re;
a.im += b.im;
return a;
}
``````

In the body of `+`, `a` is the copy of the call argument and hence changes to `a` do not affect the argument:

``````unittest
{
var a = Complex(2.0, 1.0);
var b = Complex(1.0, -2.0);
var c = a + b;

assert(c == Complex(3.0, -1.0));
// a does not change
assert(a == Complex(2.0, 1.0));
}
``````

Our second example makes more use of methods that change the state of a `struct` value.

``````struct Counter
{
var value: int;

property count(): int
{
return value;
}

func incr(): void
{
value += 1;
}

func reset(): void
{
value = 0;
}
}

unittest
{
var c: Counter;
assert(c.count == 0);
c.incr();
c.incr();
assert(c.count == 2);
c.reset();
assert(c.count == 0);
}
``````

### Classes

A class for implementing linked lists may be defined as follows:

``````class Node
{
var data: int;
var next: Node;

func new(data_: int, next_: Node)
{
data = data_;
next = next_;
}

func new(data_: int)
{
this.new(data_, null); // Call the other constructor
}

func length(): int
{
return if (next != null) 1 + next.length() else 1;
}

func last(): Node
{
return if (next == null) this else next.last();
}

func append(list: Node): void
{
last().next = list;
}
}
``````

Functions called `new` are constructors. The keyword `new` is also used to create a class instance:

``````unittest
{
var list = new Node(1, new Node(2, new Node(3)));
list.append(new Node(4));
assert(list.length() == 4);
}
``````

A constructor may call another one, prefixing `new` with `this` as in the second constructor of `Node` (or with `super` when calling a superclass constructor, see Section Inheritance).

Classes that have no explicit constructor are created as if they had one with no arguments:

``````class Empty {}

unittest
{
var e = new Empty();
var e2 = new Empty;  // equivalent to the above, empty parentheses are optional
}
``````

### Value semantics vs reference semantics

The difference in the syntax for creating struct and class values reflects the difference between the "value semantics" of the former vs the "reference semantics" of the latter:

• Variables of a struct type are a "storage" for struct members while variables of a class type are "referenes" to class instances.
• Struct values are allocated on the stack of the enclosing function while class instances are allocated on the program heap.
• The default value of a struct type is a struct value with members initialized to default values of their respective types, while the default value of a class type is the `null` reference.

## More on classes and structs

The following sections may safely be skipped on first reading.

### Access modifiers and nesting

Members of a class or struct may be declared `public` or `private`, `private` being the default. `private` members are inaccessible outside the module in which the aggregate type is declared. An additional modifier `protected` allowed only for class members will be discussed in Inheritance.

`static` modifier separates the field from the class/struct instance, quite similar to C++ practice:

``````class Countess
{
var iCount: int;
static var cCount: int;

public func instanceCount(): int
{
return iCount;
}

public static func classCount(): int
{
// return iCount; // would not compile
return cCount;
}
}
``````

`abstract`, `final` and `override` modifiers can be applied to classes, member functions and/or properties—this will be discussed in detail in following sections.

Since classes can be nested, `public`, `private` and `static` modifiers apply as expected (again, see Inheritance for anonymous classes used below):

``````class Outer
{
var data: text;
static var sData: text;

public class NestedNonstatic
{
public func ownersData()
{
}
}

public static class NestedStatic
{
public func ownersClassData()
{
return sData; // OK
}
}
}

unittest
{
// var object = new Outer.NestedNonstatic(); // would not compile - no access to this
var object = new Outer.NestedStatic(); // OK
var iAmAThis = new class Outer
{
public func new()
{
var nestedNonstaticInstance = new NestedNonstatic(); // OK - I have a this here
}
};

// to construct Outer.NestedNonstatic here we need to provide an instance of Outer explicitly
var outer = new Outer;
var object2 = outer.new Outer.NestedNonstatic();
}
``````

### Argument passing

As mentioned before classes are passed to and returned from functions by reference, whilst structs by value. The following should therefore be no surprise:

``````func decr(c: Countess)
{
c.iCount -= 1; // will modify on the outside this function
}

func decr(c: Counter)
{
c.value -= 1; // change will not be visible outside this function
}

unittest
{
var cter = Counter(1);
assert(cter.count == 1);
decr(cter);
assert(cter.count == 1);

var ctess = new Countess;
ctess.iCount = 1;
decr(ctess);
assert(ctess.iCount == 0);
}
``````

### Destructors and scope modifier

Classes may define destructors to provide behaviour on destruction of the object, by having a `delete` member function. Since Morfa is garbage collected, the moment when the destructor is called is unknown, unless `scope` modifier is used for a variable.

Take care not to return from a function nor otherwise extend the accessibility of an object pointed by a `scope var` variable.

``````class Destructy
{
var data: text;

func new()
{
data = "Fresh, just constructed";
}

func delete()
{
data = "GC got me. Will be destroyed and dealocated";
}
}

unittest
{
var willBeDeletedAsGCWishes = new Destructy;
scope var willBeDeletedOnLeavingUnittest = new Destructy;
}
``````