Thread overview
Unintuitive behavior with shared classes & template member functions; is this intended?
6 days ago
Jaime
4 days ago
Jaime
6 days ago

Some code that produces the strange behavior I'm seeing:

shared class MyClass {
    this() {}
    this(As...)(As args) if (As.length > 0) {}
}

void main() {
    pragma(msg, typeof(new MyClass));
    pragma(msg, typeof(new MyClass(1, 2, 3, "hello world")));
    pragma(msg, typeof(new shared(MyClass)));
    pragma(msg, typeof(new shared(MyClass)(1, 2, 3, "hello world")));
}

Expected output of compilation:

shared(MyClass)
shared(MyClass)
shared(MyClass)
shared(MyClass)

Actual output of compilation:

test.d(7): Error: none of the overloads of `__ctor` are callable using a non-shared object, candidates are:
test.d(2):        `test.MyClass.this()`
test.d(3):        `__ctor(As...)(As args)`
  with `As = ()`
  must satisfy the following constraint:
`       As.length > 0`
_error_
MyClass
shared(MyClass)
test.d(10): Error: none of the overloads of `this` are callable using argument types `(int, int, int, string) shared`, candidates are:
test.d(2):        `test.MyClass.this()`
test.d(3):        `__ctor(As...)(As args)`
_error_

Compiler version: 64-bit, v2.096.1, on Linux

What this seems to illustrate is that template member functions of a shared class are not implicitly shared. Alarmingly, this example illustrates this is true specifically for template constructors, meaning if a shared class has a template constructor that's not explicitly shared, it's possible to construct a non-shared instance of the shared class.

Why does this happen? Is it intended behavior? I'm still somewhat new to D, so I'm not prepared to submit this as an issue quite yet; for all I know, there might be a good reason it works this way.

This confusing problem really bit me in the patootie in a personal project earlier. Fortunately, although it was difficult to guess what was going on, once I did, it was an easy fix: namely, a template member function explicitly marked as shared is, of course, compiled as shared, as desired.

6 days ago

On 1/14/22 6:10 PM, Jaime wrote:

>

Why does this happen? Is it intended behavior? I'm still somewhat new to D, so I'm not prepared to submit this as an issue quite yet; for all I know, there might be a good reason it works this way.

This seems like a bug to me.

>

This confusing problem really bit me in the patootie in a personal project earlier. Fortunately, although it was difficult to guess what was going on, once I did, it was an easy fix: namely, a template member function explicitly marked as shared is, of course, compiled as shared, as desired.

I think it always be shared.

Alarmingly, if you have a method, you can't call it on your newly constructed non-shared object (because the object isn't shared, but the method is).

shared classes on their own are kind of junk. It's supposed to mean that everything is shared inside, but you probably can fix the issue via:

class C
{
shared:
   ... // everything
}

Please file: https://issues.dlang.org

-Steve

4 days ago

On Saturday, 15 January 2022 at 02:52:20 UTC, Steven Schveighoffer wrote:

>

you probably can fix the issue via:

class C
{
shared:
   ... // everything
}

This seems like a good solution. To achieve implicit sharing on the aggregate itself, I can use this approach to define a Voldemort type, and declare the intended name as an externally visible alias to that type.

Something like this (untested):

alias MyClass = shared(typeof(({
    class MyInvisibleClass {shared {
        // things
    }}
    return cast(MyInvisibleClass)(null);
})()));

Whether this is a good thing to do, of course, is debatable.

>

Please file: https://issues.dlang.org

-Steve

Unfortunately I cannot; despite my repeated attempts, the Bugzilla instance is not sending me a confirmation email to register an account. This problem has persisted for a day or so, so I doubt the emails will eventually come through.

I apologize. If anyone reading would care to file this issue on my behalf, I would be much obliged.