Skip to content

Working in a @nogc environment

Guillaume Piolat edited this page Jul 20, 2017 · 34 revisions

Probably the largest hurdle to cross when learning Dplug is getting used to working without the runtime enabled. It may be confusing or even a little frustrating at first, but once you learn a few key tricks, it's a breeze. Here are some important things to remember when writing Plug-ins with Dplug.

Dplug does not use the -betterC switch but instead let the runtime disabled. The term "runtime-free D" has been coined (as opposed to "runtime-less"). This allows to get back most features of the language, except for heap closures. No runtime enabled implies no GC.

Allocating Memory

Aligned memory

Dplug generally uses malloc throughout, however some construct use alignedMalloc, alignedRealloc and alignedFree.

Don't mix and match memory allocated with malloc and memory allocated with alignedMalloc.

Slices

Slices can be allocated using malloc/free, and the functions mallocSlice, mallocSliceNoInit, and freeSlice provides are wrappers to do just that.

Example:

float[] myBuf = mallocSliceNoInit(128);

// later
freeSlice(myBuf);

Another handy way to allocate audio buffer is to use reallocBuffer. This function also takes an alignment.

Example:

float[] myAudioBuf;
myAudioBuf.reallocBuffer(frames, 16); // takes optional alignment (default = 1)

// later
myAudioBuf.reallocBuffer(0, 16);      // must repeat alignment

Getting back Classes

Since there is no runtime enabled (hence no GC) the keyword new cannot be used to allocate memory for classes. Instead classes must be allocated using auto mallocNew(T, Args...)(Args args).

Once you are finished using the class, you may deallocate it using void destroyFree(T)(T p)

Example:

class Foo
{
public:
    this(int i)
    {
        f = i;
    }
private:
    int f;
}

// Create a new object of type foo and pass 3 to its constructor.
Foo foo = mallocNew!Foo(3);

// Done using the class so the memory can be freed.
foo.destroyFree();

Getting back Array Literals

See: https://p0nce.github.io/d-idioms/#@nogc-Array-Literals:-Breaking-the-Limits

Getting back Exceptions

If you need exception in runtime-free D, use the following construct:

Example:

try
{
    if (error)
        throw mallocEmplace!Exception("An error message without format() call");
}
catch(Exception e)
{
    // do something with e
    e.destroyFree();
}

Standard Library

One disadvantage to using @nogc is that it makes much of the standard library off limits. If you are unsure of what you can and can't use, you can check the documentation here Phobos Documentation, if the function is nothrow @nogc then it can be used. Most of the core modules can be used, and everything in core.stdc is nothrow @nogc.

Note that template functions have their attributes inferred most of the time: https://p0nce.github.io/d-idioms/#Automatic-attribute-inference-for-function-templates

CTFE

An exception to these rules is when using CTFE(Compile-Time Function Evaluation). Since the D runtime is available during compile time, it is possible to use every feature using the GC: new, heap closures, array literals, GC slices, etc.

Another exception is host application (using dplug:host), will have the runtime enabled.

In general, nothrow @nogc code can be used both by regular code using the runtime and nothrow @nogc code.