# Writing classes

- Source file organization
- Virtual classes
- Class source file contents
  - Header contents
  - Source contents
- Class description
  - Class declaration
  - Inheritance
  - Constants
  - Properties
  - Methods
  - Events
- Class implementation
  - Implementing a method
  - Implementing a property

## Source file organization

Once the component object model is clearly defined, you can start implementing the classes.

The best method is to have one source file and one header file for each class and its related virtual classes. See below for more information about virtual classes.

Here is an extract from the Qt component source directory:

      $ pwd
      ~/gambas/src/lib/qt
      $ ls
      CButton.cpp       CIconView.cpp     CScreen.cpp      main.cpp
      CButton.h         CIconView.h       CScreen.h        main.h
      ...

You can declare several classes in the same file, but you should generally avoid it. Things are clearer that way.

## Virtual classes

What is a virtual class? It is a class which represents a sub-component of a class, but which you cannot instanciate nor reference into a variable. For example, the property `Item` of the Qt component `ListBox` class is a virtual class that represents a `ListBox` item.

Virtual classes are just used as datatypes by the interpreter. But the object used behind is the real object coming from the real non-virtual class. For example, the Item property of the `ListBox` class stores the index of the item you want to deal with in the `ListBox` object, and returns this `ListBox` object. The `ListBox` object becomes then a virtual class object that you cannot store in a variable. As you must use the virtual class object immediately, by calling a method or a property on it, the stored index will be used immediately too.

This mechanism has been designed so that the user manipulates temporary objects, without being compelled to create them. It is SO much faster!

Note that the name of a virtual class must begin with a dot. For example, the name of the virtual class used by the `Item` property is `.ListBoxItem`.

## Class source file contents

A class source file contains:

- The declaration of the class and each related virtual class.
- The implementation of each method and properties.
- Any static function, variable or class (in C++) related to the class implementation.

### Header contents

The structure of the class header file is as follows:

      /* MyClass.h */

      #ifndef __MYCLASS_H
      #define __MYCLASS_H

Include `main.h` there, and any other includes needed by the declarations located in this file.

      #include "main.h"

If the class is instanciable, declare the structure of your objects. Note that the structure must begin with a GB_BASE field, and that the other fields are free.

      typedef
        struct {
          GB_BASE ob;
          ...
          }
        MyClassStruct;

`main.c` will include the class include files, so it must have an access to the class description.

      #ifndef __CEXAMPLE_C
        extern GB_DESC MyClass[];
        extern GB_DESC MyVirtualClassDesc[];

Otherwise, you can declare useful macros that helps writing the class implmentation. For example, the followinf constant makes the code more readable. Note that it can only be used where `_object` is declared, i.e. inside a method or property implementation.

      #else
        #define THIS ((MyClassStruct *)_object)
      #endif

      #endif /* __MYCLASS_H */

### Source contents

The structure of the class source file is as follows:

      /* MyClass.c */

      #define __CEXAMPLE_C

Include the class header file, and any other include files needed by the contents of the source file.

      #include <stdio.h>
      #include <stdlib.h>
      ...

      #include "MyClass.h"

If your class raises events, you must declare them with the DECLARE_EVENT macro.

      DECLARE_EVENT(FirstEvent);
      DECLARE_EVENT(SecondEvent);
      ...

Include any static functions that may be needed by your implementation.

      static void do_job(...)
      {
       ...
      }

Then write the implementation of each method and property.

      BEGIN_METHOD(...)
       ...
      END_METHOD

      BEGIN_PROPERTY(...)
       ...
      END_METHOD

Finally, the last part of the class source file is the declaration of its description.

A class description is an array of GB_DESC structure filled with special macros declared in `gambas.h`

      GB_DESC MyClassDesc[] =
      {
        GB_DECLARE("MyClass", sizeof(MyClassStruct)),
        ...
        GB_END_DECLARE
      };

## Class description

The class description must begin with a `GB_DECLARE` macro and end with a `GB_END_DECLARE` macro.

### Class declaration

Use the `GB_DECLARE` macro to declare the name of the class and the size of its object.

If the class is virtual, add a line with the `GB_VIRTUAL_CLASS` macro. Don't forget that the class name must begin with a dot, and the size of the object must be equal to zero.

If the class is normal, but not creatable by the user, add a line with the `GB_NOT_CREATABLE` macro.

Then you add a declaration line for each class symbol.

### Inheritance

Your class can inherit from another class, by using the `GB_INHERITS` macro and specifying the parent class name.

A class inherits from its parent all methods, properties, constants and events.

Moreover, the class object structure must include the parent object structure at its beginning. Otherwise, the inheritance will not work!

Example:

The TreeView class inherits from the Control.

The `Control` object structure is as follows:

      typedef
        struct {
          GB_BASE ob;
          QWidget *widget;
          ...
          }
        CWIDGET;

And the `TreeView` object structure is as follows:

      typedef
        struct {
          CWIDGET widget;
          ...
          }
        CTREEVIEW;

### Constants

A constant is depicted by its name, its type and its value.

To declare a constant, use the `GB_CONSTANT` macro.

See the macro description for more information.

### Properties

A property is depicted by its name, its type, and its implementation function.

To declare a property, use the `GB_PROPERTY` macro, or the `GB_STATIC_PROPERTY` macro if the property is static.

If the property is read-only, you must use the `GB_PROPERTY_READ` or `GB_STATIC_PROPERTY_READ` macro instead.

If you want a special property that returns the same object as a virtual class, use the `GB_PROPERTY_SELF` or `GB_STATIC_PROPERTY_SELF` macro.

See the macro description for more information.

### Methods

A method is depicted by its name, its return type, its signature and its implementation function.

To declare a method, use the `GB_METHOD` macro, or the `GB_STATIC_METHOD` macro if the method is static.

See the macro description for more information.

### Events

An event is depicted by its name, its return type, and its signature.

To declare an event, use the `GB_EVENT` macro. This macro takes a variable pointer as an argument to let the interpreter allocate an identifier to this event. This variable must be declared in the source file with the `DECLARE_EVENT` macro.

See the macro descriptions for more information.

## Class implementation

### Implementing a method

To implement a method, you must write a function whose code is enclosed between the two macros: `BEGIN_METHOD` and `END_METHOD`.

The `BEGIN_METHOD` macro takes TWO arguments: the function name, and a list of arguments separated by semicolons.

The method arguments are NOT separated by commas, because they are in reality fields of a structure passed to the function.

If your method takes no argument, you must use the `BEGIN_METHOD_VOID` instead of `BEGIN_METHOD`. The `BEGIN_METHOD_VOID` macro takes only one argument, the name of the function.

The `gambas.h` include file contains definitions for the argument types:

- `GB_BOOLEAN` for a boolean argument.
- `GB_INTEGER` for an integer argument.
- `GB_FLOAT` for a double argument.
- `GB_STRING` for a string argument.
- `GB_DATE` for a date argument.
- `GB_VARIANT` for a variant argument.
- `GB_OBJECT` for a object reference.

You MUST use these datatypes!

To get the parameters, you have two macros : `ARG()` and `VARG()`.

The `ARG()` macro returns the address of the parameter in the interpreter stack, and is used with functions like `GB.ToZeroString()`, or `GB.Store()`.

The `VARG()` macro returns the value of the parameter.

Example :

      BEGIN_METHOD ( TheFunctionName , GB_INTEGER anInteger; GB_STRING aString; GB_VARIANT aVariant; GB_BOOLEAN aBoolean; )

To get the value of a parameter, you must use the `VARG` macro.

        printf("anInteger = %d\n", VARG(anInteger));

To get a string parameter, you must use the special macros `STRING` and `LENGTH` to get the address of the string and its length.

        printf("aString = %*.s\n", LENGTH(aString), STRING(aString));

You can also transform the Gambas string into a C zero-terminated string with the `GB.ToZeroString` function. You must use the `ARG` macro to get the parameter address, and not the `VARG` macro that returns its value.

        printf("aString = %.s\n", GB.ToZeroString(ARG(aString)));

`GB_VARIANT` is a union of different datatypes. The type field of this union is one of the GB_T_* constants.

        if (VARG(aVariant).type == GB_T_STRING)
          printf("I got the following string: %s\n", VARG(aVariant)._string.value);

`GB_BOOLEAN` is stored as an integer, which is zero when `FALSE`, and different from zero when `TRUE`.

        printf("aBoolean = %s\n", VARG(aBoolean) ? "TRUE" : "FALSE");

If you want to raise an error into your method, you must use the `GB.Error()` function to register the error, and returns immediately after.

      if (VARG(aBoolean))
      {
        GB.Error("There was an error!");
        return;
      }

To return a value from the method, you can use the `GB.Return<Type>()` interface functions: `GB.ReturnInteger()` to return a integer, `GB.ReturnBoolean()` to return a boolean, and so on.

        GB.ReturnInteger(VARG(anInteger) * 2);

    END_METHOD

### Implementing a property

To implement a property, you must write a function whose code is enclosed between the two macros : `BEGIN_PROPERTY` and `END_PROPERTY`.

The `BEGIN_PROPERTY` macro takes one argument: the property name.

The function is called both for reading and writing the property. To distinguish between the two cases, you must use the `READ_PROPERTY` macro. Of course, if your property is read-only, this is not necessary.

When reading the property, you must return the property value with one of the `GB.Return<Type>` functions.

When writing the property, you get the value to write with the `VPROP` macro. This macro takes one argument: the datatype of the property, which must be one of the Gambas value structure defined in `gambas.h` :

- `GB_BOOLEAN` for a boolean argument.
- `GB_INTEGER` for an integer argument.
- `GB_FLOAT` for a double argument.
- `GB_STRING` for a string argument.
- `GB_DATE` for a date argument.
- `GB_VARIANT` for a variant argument.
- `GB_OBJECT` for a object reference.

Use the `PROP` macro to get the address of the value, if you want to use functions like like `GB.ToZeroString()`, or `GB.Store()`.

Example:

      BEGIN_PROPERTY ( ThePropertyName )

First, you must check if we want to read or to write the property.

        if (READ_PROPERTY)
        {

Here we are reading the property...

          printf("Returning the property value\n");

The `THIS` macro is defined in the class header file. It returns a pointer to the data of the object structure.

We suppose here that there is a `char * AStringProperty` defined in the object structure, that points to a Gambas string.

          GB.ReturnString(THIS->AStringProperty);
        }
        else
        {

Here we are writing the property...

To store a complex Gambas datatype like `String` or `Object`, you must use `GB.StoreString()` or `GB.StoreObject()`. These functions deal with reference counting.

          printf("I'm going to write the value: %s\n", GB.ToZeroString(PROP(GB_STRING)));

          GB.StoreString(PROP(GB_STRING), &THIS->AStringProperty);

Generally, a modified property implies some other actions...

          printf("Property has been modified. The new value is %s\n", THIS->AStringProperty);
        }

      END_PROPERTY