[[PageOutline]] = Classes = One of MiniD's goals is to create a simple-to-use object-oriented method of programming. It accomplishes this through classes, which mimic classes in D, but are much simpler. The syntax for class declarations is as follows: {{{ ClassDeclaration: ['local' | 'global'] 'class' Identifier [':' Expression] '{' {ClassMember} '}' ClassMember: SimpleFunctionDeclaration Identifier ['=' Expression] ';' 'this' Parameters BlockStatement }}} == Class Declarations == Class declarations follow the same pattern found in C++ and D. A class is given a name, optionally followed by a colon with the base class's name, and then a block containing the members of the class. Where the class actually ends up is dependent upon whether it's preceded by a 'local' keyword, a 'global' keyword, or neither. If it's declared 'local' or with no preceding keyword, a new local is created and the class is placed in it. If it's declared 'global', a new global is created and the class is placed in it. See [wiki:LanguageSpec/Functions Functions] for more information on this. == Fields == Fields are the data members of the class. Their declaration is very similar to that of table fields, and their initializers can be any expression (not just constant expressions as in D). {{{ #!minid class A { mX = 0; mY = 0; mZ; } }}} Class `A` has three fields, named `mX`, `mY`, and `mZ`. mX and mY will be initialized to 0, and mZ to `null`. When you instantiate A (which is achieved by simply calling A as if it were a function), the instance will have copies of all the fields defined in the class. Remember that the member initializers are only run at the point of the class definition, however, and not whenever the class is instanced. This is important to remember when dealing with members which need to be instances of new reference types for each instance, for example. Since classes are objects themselves, they are dynamically modifiable. Class members can be added and their values changed at any time: {{{ #!minid class A { mX = 0; mY = 0; mZ; } local a1 = A(); // this has mX, mY, and mZ A.mZ = 5; local a2 = A(); // this has the same members, but now mZ is 5. A.mW = 0; local a3 = A(); // this has mX, mY, mZ, and mW. a1.mW = 6; // error, a1 does not have mW (since it was instantiated before that change) }}} You may not define a field more than once in a class. == Member Functions == When you declare functions in a class, they become member functions. These are functions which can be called using an instance of the class. Because of the way the implicit `this` parameter and global lookup work (see [wiki:LanguageSpec/Functions Functions]), you can access class members and call other class member functions without explicitly qualifying `this`: {{{ #!minid class A { mX = 0; function printX() { writefln("x: ", this.mX); } function printX2() { writefln("x: ", mX); } function callPrintX() { printX(); } } local a = A(); // all three print "x: 0" a.printX(); a.printX2(); a.callPrintX(); }}} You may not define a method more than once in a class. == Constructors == Classes can define a constructor (one constructor and no more), which is a member function which is run upon instantiation of the class. You can either declare a constructor by making a method named "constructor" or by using the D-style "`this()`" syntax: {{{ #!minid class A { mX = 0; mY = 0; function constructor(x, y) { mX = x; mY = y; } } local a = A(3, 4); writefln(a.mX, ", ", a.mY); // prints "3, 4" class B { this(x, y) { writefln("B ctor: ", x, ", ", y); } } B(2, 5); // prints "B ctor: 2, 5" }}} The "`this()`" form is just syntactic sugar for the longer (and easier to mess up) "`function constructor()`" form. Because it's easy to mistype the "`function constructor`" form, it's recommended to use the "`this()`" form instead. But keep in mind that if you want to get the constructor of a class for some reason, you access the member named "constructor," regardless of how it was defined. The constructor is just another class method. Calling the constructor does not instantiate the class. You instantiate the class by calling the class as if it were a function; when this happens, the constructor (if any) is called on the instance after it has been created. You can actually call the constructor on an already-existing instance at any time. This can sometimes be useful; for example, if you're constantly needing new instances of a class, but you don't need many instances at one time, you can simply re-initialize an old instance by calling the constructor on it. == Base Class == MiniD's classes support single inheritance: each class can inherit from at most one other class. If a class doesn't inherit from any other class, it simply has no base class. You can retrieve the base class of any class or instance value by using "`.super`" on them, as if it were a property: {{{ #!minid class A {} class B : A {} writefln(A.super); // prints 'null' writefln(B.super); // prints 'class A' local b = B(); writefln(b.super); // again prints 'class A' }}} You can use a super call expression to call a base class's constructor: {{{ #!minid class Base { mX = 0; this() { writefln("Base ctor ", mX); } } class Derived : Base { this() { mX = 5; writefln("Derived ctor"); super(); } } local d = Derived(); }}} This will output: {{{ Derived ctor Base ctor 5 }}} Also, if a derived class declares no constructor but its base class does, because of the way inheritance works, the derived class's constructor will simply be the same as the super class. So there is no need to create a dummy "forwarding" constructor. {{{ #!minid class Base { this() { writefln("Base ctor"); } } class Derived : Base { } local d = Derived(); // writes "Base ctor" }}} If you wish to access the base class's implementation of a certain method, you can do so with another form of the super call expression, which looks exactly the same as the corresponding D code: {{{ #!minid class Base { function fork() { writefln("Base fork."); } } class Derived : Base { function fork() { writefln("Derived fork!"); super.fork(); } } local d = Derived(); d.fork(); }}} Actually, since the class constructor is nothing more than another method, the super constructor call is just sugar for "`super.constructor(...)`".