Thread overview
Debug help - Programming in D page 633 - concurrency shared(Exception) warnings
16 hours ago
Brother Bill
6 hours ago
Brother Bill
16 hours ago

If this technique is still valid, I need the code modernized so that it works without warnings. I'm still in the D learning curve, so I don't quite know what is being warned, and how to clean up the mess.

I believe that the new code runs properly, but it would be nice for it to be 'warning free'.

The prior source/app.d which runs is

import std.stdio;
import std.concurrency;
import std.conv;

struct CalculationFailure
{
    string reason;
}

struct Exit
{
}

void calculate()
{
    bool isDone = false;

    while (!isDone)
    {
        receive((string message) {
            try
            {
                ownerTid.send(to!double(message) + 0.5);
            }
            catch (Exception exc)
            {
                ownerTid.send(CalculationFailure(exc.msg));
            }
        },
            (Exit message) { isDone = true; });
    }
}

void main()
{
    Tid calculator = spawn(&calculate);
    calculator.send("1.2");
    calculator.send("hello"); // ← incorrect input
    calculator.send("3.4");
    calculator.send(Exit());

    foreach (i; 0 .. 3)
    {
        writef("result %s: ", i);
        receive(
            (double message) { writeln(message); },

            (CalculationFailure message) {
            writefln("ERROR! '%s'", message.reason);
        });
    }
}

When run, this is the output:

result 0: 1.7
result 1: ERROR! 'no digits seen for input "hello".'
result 2: 3.9

The goal is to modify source/app.d so that it includes this snippet

// ... at the worker ...
 try {
    // ...
 } catch (shared(Exception) exc) {
    ownerTid.send(exc);
 }},

 // ... at the owner ...
 receive(
 // ...
    (shared(Exception) exc) {
       throw exc;
 });

The new merged source/app.d for main() is

void main()
{
    Tid calculator = spawn(&calculate);
    calculator.send("1.2");
    calculator.send("hello"); // ← incorrect input
    calculator.send("3.4");
    calculator.send(Exit());

    foreach (i; 0 .. 3)
    {
        writef("result %s: ", i);

		// ... at the owner ...
        receive(
            (double message) { writeln(message); },

            // (CalculationFailure message) {
            // 	writefln("ERROR! '%s'", message.reason);
        	// },

			(shared(Exception) exc) {
				throw exc;
			}
		);
    }
}

The console output is:

c:\dev\D\81 - 90\c85_7d_exceptions_catch_send_exception_to_owner\source\app.d(26): Deprecation: can only catch mutable or const qualified types, not `shared(Exception)`
            catch (shared(Exception) exc)
            ^
c:\dev\D\81 - 90\c85_7d_exceptions_catch_send_exception_to_owner\source\app.d(56): Deprecation: cannot throw object of qualified type `shared(Exception)`
                throw exc;
                      ^
c:\dev\D\81 - 90\c85_7d_exceptions_catch_send_exception_to_owner\source\app.d(26): Deprecation: can only catch mutable or const qualified types, not `shared(Exception)`
            catch (shared(Exception) exc)
            ^
c:\dev\D\81 - 90\c85_7d_exceptions_catch_send_exception_to_owner\source\app.d(56): Deprecation: cannot throw object of qualified type `shared(Exception)`
                throw exc;
                      ^
result 0: 1.7
result 1:
std.conv.ConvException@C:\D\dmd2\windows\bin64\..\..\src\phobos\std\conv.d(3360): no digits seen for input "hello".
14 hours ago

A note on your references here:

I'm assuming you are working from a physical book. But the online book is here: https://ddili.org/ders/d.en/index.html

When you have questions, if you could link to the content, that would be really helpful. Especially since you are not including the entire material.

For this one, the content is here: https://ddili.org/ders/d.en/concurrency.html

On Saturday, 30 August 2025 at 01:38:35 UTC, Brother Bill wrote:

>

If this technique is still valid, I need the code modernized so that it works without warnings. I'm still in the D learning curve, so I don't quite know what is being warned, and how to clean up the mess.

I believe that the new code runs properly, but it would be nice for it to be 'warning free'.

>

The goal is to modify source/app.d so that it includes this snippet

// ... at the worker ...
 try {
    // ...
 } catch (shared(Exception) exc) {
    ownerTid.send(exc);
 }},

 // ... at the owner ...
 receive(
 // ...
    (shared(Exception) exc) {
       throw exc;
 });

The new merged source/app.d for main() is

void main()
{
    Tid calculator = spawn(&calculate);
    calculator.send("1.2");
    calculator.send("hello"); // ← incorrect input
    calculator.send("3.4");
    calculator.send(Exit());

    foreach (i; 0 .. 3)
    {
        writef("result %s: ", i);

		// ... at the owner ...
        receive(
            (double message) { writeln(message); },

            // (CalculationFailure message) {
            // 	writefln("ERROR! '%s'", message.reason);
        	// },

			(shared(Exception) exc) {
				throw exc;
			}
		);
    }
}

Tid can only send or receive shared or immutable data. This is a long standing requirement, and it makes sense.

The thing is, this data is shared only when it is going through the message system. Once it's out, you can remove the shared because the sender has forgotten it.

So the solution is to cast to shared only for transmitting. That is, you cast to shared to send, and then cast away from shared on the other side after you receive.

It is imperative that you forget the data you have sent (the exception) from the sender, as now it can't be considered shared any more.

Also note, that you shouldn't catch the shared exception directly, just catch a normal exception and cast it.

Why require the casting? Because there is no language mechanism to validate a shared piece of data, or anything it contains is not still referenced. We rely on the user to tell the compiler via a cast.

-Steve

6 hours ago

On Saturday, 30 August 2025 at 03:21:14 UTC, Steven Schveighoffer wrote:

>

Tid can only send or receive shared or immutable data. This is a long standing requirement, and it makes sense.

The thing is, this data is shared only when it is going through the message system. Once it's out, you can remove the shared because the sender has forgotten it.

So the solution is to cast to shared only for transmitting. That is, you cast to shared to send, and then cast away from shared on the other side after you receive.

It is imperative that you forget the data you have sent (the exception) from the sender, as now it can't be considered shared any more.

Also note, that you shouldn't catch the shared exception directly, just catch a normal exception and cast it.

Why require the casting? Because there is no language mechanism to validate a shared piece of data, or anything it contains is not still referenced. We rely on the user to tell the compiler via a cast.

-Steve

I tried various code changes, none of which worked.
Kindly provide code changes to fix warnings that reflect modern D programming.