Thread overview
Newbie problem
Jun 19, 2013
Roger Stokes
Jun 19, 2013
Adam D. Ruppe
Jun 19, 2013
Roger Stokes
Jun 19, 2013
Ali Çehreli
Jun 20, 2013
Roger Stokes
Jun 19, 2013
Adam D. Ruppe
Jun 20, 2013
Roger Stokes
June 19, 2013
I'd be grateful for advice. The problem is that I can't get the example
on page 406-7 of the"The D Programming Language " to compile.
I've cut and pasted the text from the website, and corrected the typo (undefined tgt, so use stdout instead).  I get this diagnostic:

page406x.d(11): Error: cannot implicitly convert expression (__r24.front()) of type ubyte[] to immutable(ubyte)[]

from this input:

import std.algorithm, std.concurrency, std.stdio;

void main() {
   enum bufferSize = 1024 * 100;
   auto tid = spawn(&fileWriter);
   // Read loop
   foreach (immutable(ubyte)[] buffer; stdin.byChunk(bufferSize)) {
      send(tid, buffer);
   }
}

void fileWriter() {
   // Write loop
   for (;;) {
      auto buffer = receiveOnly!(immutable(ubyte)[])();
      stdout.write(buffer);
   }
}
June 19, 2013
On Wednesday, 19 June 2013 at 15:25:15 UTC, Roger Stokes wrote:
> page406x.d(11): Error: cannot implicitly convert expression (__r24.front()) of type ubyte[] to immutable(ubyte)[]

>    foreach (immutable(ubyte)[] buffer; stdin.byChunk(bufferSize)) {


The problem here is that byChunk returns a mutable buffer, type ubyte[]. If you said "foreach(ubyte[] buffer; stdin.byChunk(bufferSize)) {...}" you should be able to compile it.

I think this was changed after the book was written because byChunk now reuses its buffer. Each time through the loop, it overwrites the old data with the next batch, which means the old data cannot be immutable. (The reason for reusing it is to avoid allocating new memory for a fresh buffer every time.)

Since you aren't keeping a copy of the buffer, just changing the type should be enough for your program to work.

If you needed an immutable copy, if you were going to store it or something, the way you'd do that is to call buffer.idup:

foreach(ubyte[] temporaryBuffer; stdin.byChunk(bufferSize) {
     immutable(ubyte)[] permanentBuffer = temporaryBuffer.idup;
    // you can now use the permanentBuffer
}
June 19, 2013
Many thanks for swift response. I'm still in difficulty, alas.  There were two
possibilities suggested: firstly,

> Adam D. Ruppe wrote:

> The problem here is that byChunk returns a mutable buffer, type ubyte[]. If you said "foreach(ubyte[] buffer; stdin.byChunk(bufferSize)) {...}" you should be able to compile it.
>
 I tried this, which I hope is correct: ---------------------------

void main() {
   enum bufferSize = 1024 * 100;
   auto tid = spawn(&fileWriter);
   // Read loop
   foreach (ubyte[] buffer; stdin.byChunk(bufferSize)) {
      send(tid, buffer);
   }
}

void fileWriter() {
   // Write loop
   for (;;) {
      auto buffer = receiveOnly!(immutable(ubyte)[])();
      stdout.write(buffer);
   }
}

------------------------------------------------------------
and got this compiler diagnostic:

c:\D\dmd2\windows\bin\..\..\src\phobos\std\concurrency.d(571): Error: static assert  "Aliases to mutable thread-local data not allowed."
page406x.d(12):        instantiated from here: send!(ubyte[])

For the second possibility,  ...

> Since you aren't keeping a copy of the buffer, just changing the type should be enough for your program to work.
>
> If you needed an immutable copy, if you were going to store it or something, the way you'd do that is to call buffer.idup:
>
> foreach(ubyte[] temporaryBuffer; stdin.byChunk(bufferSize) {
>      immutable(ubyte)[] permanentBuffer = temporaryBuffer.idup;
>     // you can now use the permanentBuffer
> }

I tried this ---------------------------------------------------
import std.algorithm, std.concurrency, std.stdio;

void main() {
   enum bufferSize = 1024 * 100;
   auto tid = spawn(&fileWriter);
   // Read loop

   foreach(ubyte[] temporaryBuffer; stdin.byChunk(bufferSize)) {
     immutable(ubyte)[] permanentBuffer = temporaryBuffer.idup;
	
    // you can now use the permanentBuffer

      send(tid, permanentBuffer);
   }
}

void fileWriter() {
   // Write loop
   for (;;) {
      auto buffer = receiveOnly!(immutable(ubyte)[])();
      stdout.write(buffer);
   }
}
 --------------------------------

and the result compiled and executed with no error signals, but the resulting output of the file-copy was not the same as the input, it looked like this:

std.concurrency.OwnerTerminated@std\concurrency.d(248): Owner terminated
----------------
0x004068EA
0x004081B5
0x00407AB4
0x00407C6A
0x00407CA0
0x00407D1C
0x00407883
0x004068AB
0x004020E9
0x00414D51
0x00434CB4
0x76E51603 in RtlInitializeExceptionChain
0x76E515D6 in RtlInitializeExceptionChain
----------------
[47, 47, 32, 101, 120, 97, ....

....
The numbers 47, 47, 32, etc look like the ASCII indexes of the characters
which should be in the output,  not the characters themselves!

Any further help would be much appreciated.
Regards,
    Roger Stokes

June 19, 2013
On 06/19/2013 12:14 PM, Roger Stokes wrote:

> and the result compiled and executed with no error signals, but the
> resulting output of the file-copy was not the same as the input, it
> looked like this:
>
> std.concurrency.OwnerTerminated@std\concurrency.d(248): Owner terminated

For a clean exit, the owner must tell the worker that there is no more data (see struct Done below). It must then wait for it to exit (see core.thread.thread_joinAll below):

import std.stdio;
import std.concurrency;
import core.thread;

struct Done
{}

void main() {
   enum bufferSize = 1024 * 100;
   auto tid = spawn(&fileWriter);
   // Read loop
   foreach (ubyte[] buffer; stdin.byChunk(bufferSize)) {
      send(tid, buffer.idup);
   }

   tid.send(Done());

   import core.thread;
   thread_joinAll();
}

void fileWriter() {
   // Write loop
    bool done = false;

    while (!done) {
       receive(
           (immutable(ubyte)[] buffer) {
               stdout.write(buffer);
           },

           (Done _) {
               done = true;
           });
   }
}


> ----------------
> [47, 47, 32, 101, 120, 97, ....
>
> ....
> The numbers 47, 47, 32, etc look like the ASCII indexes of the characters
> which should be in the output,  not the characters themselves!

You are writing ubyte[]. What you see is the default output for such a slice. If you are sure that the data is UTF-8, then you can cast before outputting:

               stdout.write(cast(string)buffer);

Ali

June 19, 2013
On Wednesday, 19 June 2013 at 19:14:58 UTC, Roger Stokes wrote:
> and got this compiler diagnostic:

Oh, I thought you were writing to a socket. Yeah, to a different thread, D will complain if you don't make a sharable copy. So you do want to idup it...


> [47, 47, 32, 101, 120, 97, ....
>
> ....
> The numbers 47, 47, 32, etc look like the ASCII indexes of the characters
> which should be in the output,  not the characters themselves!


The reason here is this line:
>       stdout.write(buffer);

The write function changes the format based on the type of input. Since the input here is a ubyte[], it doesn't realize it is a printable string and prints the numeric values of a byte array instead.

Try stdout.write(cast(string) buffer)) and you should get what you expect. Another potential change would be to use stdin.byLine instead of stdin.byChunk. byLine returns char[], one line at a time, but it cuts off the newline character (if I remember correctly) and can complain if the input isn't valid UTF-8, so it wouldn't work right for a generic file copy function.
June 20, 2013
Many thanks, Ali

I put together your suggestions, and it all works correctly !

Thanks again.

On Wednesday, 19 June 2013 at 19:50:55 UTC, Ali Çehreli wrote:
> On 06/19/2013 12:14 PM, Roger Stokes wrote:
>
> > and the result compiled and executed with no error signals,
> but the
> > resulting output of the file-copy was not the same as the
> input, it
> > looked like this:
> >
> > std.concurrency.OwnerTerminated@std\concurrency.d(248): Owner
> terminated
>
> For a clean exit, the owner must tell the worker that there is no more data (see struct Done below). It must then wait for it to exit (see core.thread.thread_joinAll below):
>
> import std.stdio;
> import std.concurrency;
> import core.thread;
>
> struct Done
> {}
>
> void main() {
>    enum bufferSize = 1024 * 100;
>    auto tid = spawn(&fileWriter);
>    // Read loop
>    foreach (ubyte[] buffer; stdin.byChunk(bufferSize)) {
>       send(tid, buffer.idup);
>    }
>
>    tid.send(Done());
>
>    import core.thread;
>    thread_joinAll();
> }
>
> void fileWriter() {
>    // Write loop
>     bool done = false;
>
>     while (!done) {
>        receive(
>            (immutable(ubyte)[] buffer) {
>                stdout.write(buffer);
>            },
>
>            (Done _) {
>                done = true;
>            });
>    }
> }
>
>
> > ----------------
> > [47, 47, 32, 101, 120, 97, ....
> >
> > ....
> > The numbers 47, 47, 32, etc look like the ASCII indexes of
> the characters
> > which should be in the output,  not the characters themselves!
>
> You are writing ubyte[]. What you see is the default output for such a slice. If you are sure that the data is UTF-8, then you can cast before outputting:
>
>                stdout.write(cast(string)buffer);
>
> Ali

June 20, 2013
Adam, many thanks for your helpful reply.

On Wednesday, 19 June 2013 at 19:53:08 UTC, Adam D. Ruppe wrote:
> On Wednesday, 19 June 2013 at 19:14:58 UTC, Roger Stokes wrote:
>> and got this compiler diagnostic:
>
> Oh, I thought you were writing to a socket. Yeah, to a different thread, D will complain if you don't make a sharable copy. So you do want to idup it...
>
>
>> [47, 47, 32, 101, 120, 97, ....
>>
>> ....
>> The numbers 47, 47, 32, etc look like the ASCII indexes of the characters
>> which should be in the output,  not the characters themselves!
>
>
> The reason here is this line:
>>      stdout.write(buffer);
>
> The write function changes the format based on the type of input. Since the input here is a ubyte[], it doesn't realize it is a printable string and prints the numeric values of a byte array instead.
>
> Try stdout.write(cast(string) buffer)) and you should get what you expect. Another potential change would be to use stdin.byLine instead of stdin.byChunk. byLine returns char[], one line at a time, but it cuts off the newline character (if I remember correctly) and can complain if the input isn't valid UTF-8, so it wouldn't work right for a generic file copy function.