www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 20867] New: class subtyping doen't work in separate files

https://issues.dlang.org/show_bug.cgi?id=20867

          Issue ID: 20867
           Summary: class subtyping doen't work in separate files
           Product: D
           Version: D2
          Hardware: All
                OS: All
            Status: NEW
          Severity: normal
          Priority: P1
         Component: dmd
          Assignee: nobody puremagic.com
          Reporter: mingwu gmail.com

Created attachment 1791
  --> https://issues.dlang.org/attachment.cgi?id=1791&action=edit
class subtyping doen't work in separate files

Put the code on page:

https://tour.dlang.org/tour/en/multithreading/synchronization-sharing

in to queue.d, then add subtyping and a test func f():
...
    private T[] elements;
  public: alias elements this;  // add this line
...

// test f()
class T{}

void f()
{
    auto q = new shared(SafeQueue!(shared T));
    writeln(q.length);
}

If f() is in the same file queue.d, the code can compile; if it's in a separate
file, compile will fail.


$ cat queue.d
--------------------------------------------------------------------------------
import std.stdio;
import std.concurrency : receiveOnly, send,
    spawn, Tid, thisTid;
import core.atomic : atomicOp, atomicLoad;

/*
Queue that can be used safely among
different threads. All access to an
instance is automatically locked thanks to
synchronized keyword.
*/
synchronized class SafeQueue(T)
{
    // Note: must be private in synchronized
    // classes otherwise D complains.
    private T[] elements;
  public: alias elements this;

    void push(T value) {
        elements ~= value;
    }

    /// Return T.init if queue empty
    T pop() {
        import std.array : empty;
        T value;
        if (elements.empty)
            return value;
        value = elements[0];
        elements = elements[1 .. $];
        return value;
    }
}

/*
Safely print messages independent of
number of concurrent threads.
Note that variadic parameters are used
for args! That is args might be 0 .. N
parameters.
*/
void safePrint(T...)(T args)
{
    // Just executed by one concurrently
    synchronized {
        import std.stdio : writeln;
        writeln(args);
    }
}

void threadProducer(shared(SafeQueue!int) queue,
    shared(int)* queueCounter)
{
    import std.range : iota;
    // Push values 1 to 10
    foreach (i; 1..11) {
        queue.push(i);
        safePrint("Pushed ", i);
        atomicOp!"+="(*queueCounter, 1);
    }
}

void threadConsumer(Tid owner,
    shared(SafeQueue!int) queue,
    shared(int)* queueCounter)
{
    int popped = 0;
    while (popped != 10) {
        auto i = queue.pop();
        if (i == int.init)
            continue;
        ++popped;
        // safely fetch current value of
        // queueCounter using atomicLoad
        safePrint("Popped ", i,
            " (Consumer pushed ",
            atomicLoad(*queueCounter), ")");
    }

    // I'm done!
    owner.send(true);
}

void main()
{
    auto queue = new shared(SafeQueue!int);
    shared int counter = 0;
    spawn(&threadProducer, queue, &counter);
    auto consumer = spawn(&threadConsumer,
                    thisTid, queue, &counter);
    auto stopped = receiveOnly!bool;
    assert(stopped);
}

class T{}

void f()
{
    auto q = new shared(SafeQueue!(shared T));
    writeln(q.length);
}
--------------------------------------------------------------------------------




--------------------------------------------------------------------------------
import std.stdio;
import queue;

class T{}

void f()
{
    auto q = new shared(SafeQueue!(shared T));
    writeln(q.length);
}
--------------------------------------------------------------------------------
$ dmd t.d
t.d(9): Error: no property length for type shared(queue.SafeQueue!(shared(T)))

--
May 27