Non Blocking Channel Operations in D Programming Language

Our first program demonstrates non-blocking channel operations in D. Here’s the full source code:

import std.stdio;
import core.sync.channel;

void main()
{
    auto messages = new Channel!string();
    auto signals = new Channel!bool();

    // Here's a non-blocking receive. If a value is
    // available on `messages` then it will be received.
    // If not, it will immediately take the `else` case.
    if (messages.tryReceive())
    {
        writeln("received message ", messages.front);
    }
    else
    {
        writeln("no message received");
    }

    // A non-blocking send works similarly. Here `msg`
    // cannot be sent to the `messages` channel, because
    // the channel has no buffer and there is no receiver.
    // Therefore the `else` case is selected.
    string msg = "hi";
    if (messages.trySend(msg))
    {
        writeln("sent message ", msg);
    }
    else
    {
        writeln("no message sent");
    }

    // We can use multiple `if` statements to implement
    // a multi-way non-blocking select. Here we attempt
    // non-blocking receives on both `messages` and `signals`.
    if (messages.tryReceive())
    {
        writeln("received message ", messages.front);
    }
    else if (signals.tryReceive())
    {
        writeln("received signal ", signals.front);
    }
    else
    {
        writeln("no activity");
    }
}

To run the program, save it as non_blocking_channel_operations.d and use the D compiler:

$ dmd non_blocking_channel_operations.d
$ ./non_blocking_channel_operations
no message received
no message sent
no activity

In this D example, we use the Channel type from core.sync.channel to represent channels. The tryReceive and trySend methods provide non-blocking operations on these channels.

The select statement with a default case in the original example is replaced with if-else statements in D, as D does not have a direct equivalent to Go’s select. However, the behavior is similar: we attempt an operation and immediately handle the case where the operation would block.

Note that D’s channels are different from Go’s in some ways. For example, D’s channels are always buffered, so you need to specify a buffer size when creating them (which defaults to 1 if not specified). This means that in a real-world scenario, you might need to adjust the channel creation and usage to match your specific requirements.

This example demonstrates how to perform non-blocking operations on channels in D, providing a way to implement concurrent communication patterns without blocking.