# Registering a reference type

- Registering a basic reference type
- Registering an uninstanciable reference type
- Registering a single-reference type
- Registering a scoped type

See also:
  Implementing a garbage collected object

## Registering a basic reference type

The basic reference type should be registered with the following behaviours: asBEHAVE_FACTORY, asBEHAVE_ADDREF, and asBEHAVE_RELEASE. If it is desired that assignments should be allowed for the type the asBEHAVE_ASSIGNMENT behaviour must be registered as well. Other behaviours, such as math operators, comparisons, etc may be registered as needed.

    // Registering the reference type
    r = engine->RegisterObjectType("ref", 0, asOBJ_REF); assert( r >= 0 );

See also:
  The string add-on for an example of a reference type

### Factory function

The factory function is the one that AngelScript will use to instanciate objects of this type when a variable is declared. It is responsible for allocating and initializing the object memory.

The default factory function doesn't take any parameters and should return an object handle for the new object. Make sure the object's reference counter is accounting for the reference being returned by the factory function, so that the object is properly released when all references to it are removed.

    CRef::CRef()
    {
        // Let the constructor initialize the reference counter to 1
        refCount = 1;
    }

    CRef *Ref_Factory()
    {
        // The class constructor is initializing the reference counter to 1
        return new CRef();
    }

    // Registering the factory behaviour
    r = engine->RegisterObjectBehaviour("ref", asBEHAVE_FACTORY, "ref@ f()", asFUNCTION(Ref_Factory), asCALL_CDECL); assert( r >= 0 );

You may also register factory functions that take parameters, which may then be used when initializing the object.

The factory function must be registered as a global function, but can be implemented as a static class method, common global function, or a global function following the generic calling convention.

### Addref and release behaviours

    void CRef::Addref()
    {
        // Increase the reference counter
        refCount++;
    }

    void CRef::Release()
    {
        // Decrease ref count and delete if it reaches 0
        if( --refCount == 0 )
            delete this;
    }

    // Registering the addref/release behaviours
    r = engine->RegisterObjectBehaviour("ref", asBEHAVE_ADDREF, "void f()", asMETHOD(CRef,AddRef), asCALL_THISCALL); assert( r >= 0 );
    r = engine->RegisterObjectBehaviour("ref", asBEHAVE_RELEASE, "void f()", asMETHOD(CRef,Release), asCALL_THISCALL); assert( r >= 0 );

### Assignment behaviour

    CRef &CRef::operator =(const CRef &other)
    {
        // Copy everything from the other class, except the reference counter
    }

    // Registering the assignment behaviour
    r = engine->RegisterObjectBehaviour("ref", asBEHAVE_ASSIGNMENT, "ref &f(const &in)", asMETHOD(CRef,operator=), asCALL_THISCALL); assert( r >= 0 );

The assignment behaviour can be overloaded with other types if that is desired, that way the script writer doesn't have to manually convert the expressions before assigning the values to the type.

## Registering an uninstanciable reference type

Sometimes it may be useful to register types that cannot be instanciated by the scripts, yet can be interacted with. You can do this by registering the type as a normal reference type, but omit the registration of the factory behaviour. You can later register global properties, or functions that allow the scripts to access objects created by the application via object handles.

This would be used when the application has a limited number of objects available and doesn't want to create new ones. For example singletons, or pooled objects.

## Registering a single-reference type

A variant of the uninstanciable reference types is the single-reference type. This is a type that have only 1 reference accessing it, i.e. the script cannot store any extra references to the object during execution. The script is forced to use the reference it receives from the application at the moment the application passes it on to the script.

The reference can be passed to the script through a property, either global or a class member, or it can be returned from an application registered function or class method.

    // Registering the type so that it cannot be instanciated
    // by the script, nor allow scripts to store references to the type
    r = engine->RegisterObjectType("single", 0, asOBJ_REF | asOBJ_NOHANDLE); assert( r >= 0 );

This sort of type is most useful when you want to have complete control over references to an object, for example so that the application can destroy and recreate objects of the type without having to worry about potential references held by scripts. This allows the application to control when a script has access to an object and it's members.

## Registering a scoped type

Some C++ value types have special requirements for the memory where they are located, e.g. specific alignment needs, or memory pooling. Since AngelScript doesn't provide that much control over where and how value types are allocated, they must be registered as reference types. In this case you'd register the type as a scoped reference type.

A scoped reference type will have the life time controlled by the scope of the variable that instanciate it, i.e. as soon as the variable goes out of scope the instance is destroyed. This means that the type doesn't permit handles to be taken for the type.

A scoped reference type requires two behaviours to be registered, the factory and the release behaviour. The addref behaviour is not permitted.

Since no handles can be taken for the object type, there is no need to keep track of the number of references held to the object. This means that the release behaviour should simply destroy and deallocate the object as soon as it's called.

    scoped *Scoped_Factory()
    {
      return new scoped;
    }

    void Scoped_Release(scoped *s)
    {
      if( s ) delete s;
    }

    // Registering a scoped reference type
    r = engine->RegisterObjectType("scoped", 0, asOBJ_REF | asOBJ_SCOPED); assert( r >= 0 );
    r = engine->RegisterObjectBehaviour("scoped", asBEHAVE_FACTORY, "scoped @f()", asFUNCTION(Scoped_Factory), asCALL_CDECL); assert( r >= 0 );
    r = engine->RegisterObjectBehaviour("scoped", asBEHAVE_RELEASE, "void f()", asFUNCTION(Scoped_Release), asCALL_CDECL_OBJLAST); assert( r >= 0 );