November 09, 2021
On 09.11.21 16:30, Stanislav Blinov wrote:
> 
> ```d
> template isNothrowCopyable(To, From)
> if (is(immutable To == immutable From))
> {
>      enum bool isNothrowCopyable = is(typeof((ref scope From from) nothrow { union U { To to; } U u = U(from); }));
> }
> ```
> 
> ...but it indeed doesn't work for nested structs. And a thing that does "work" has to reimplement compiler's copy semantics, including field-by-field blitting, calling constructors and postblits, etc.

template isNothrowCopyable(To, From)
if (is(immutable To == immutable From))
{
    enum bool isNothrowCopyable = is(typeof((ref scope From from) nothrow { union U { auto to=To.init; } U u = U(from); }));
}
November 09, 2021
On 09.11.21 16:36, Timon Gehr wrote:
> On 09.11.21 16:30, Stanislav Blinov wrote:
>>
>> ```d
>> template isNothrowCopyable(To, From)
>> if (is(immutable To == immutable From))
>> {
>>      enum bool isNothrowCopyable = is(typeof((ref scope From from) nothrow { union U { To to; } U u = U(from); }));
>> }
>> ```
>>
>> ...but it indeed doesn't work for nested structs. And a thing that does "work" has to reimplement compiler's copy semantics, including field-by-field blitting, calling constructors and postblits, etc.
> 
> template isNothrowCopyable(To, From)
> if (is(immutable To == immutable From))
> {
>      enum bool isNothrowCopyable = is(typeof((ref scope From from) nothrow { union U { auto to=To.init; } U u = U(from); }));
> }

(I don't know if that solves your problem, as I don't actually have an example where your implementation does not work.)
November 09, 2021

On Tuesday, 9 November 2021 at 12:59:08 UTC, Alexandru Ermicioi wrote:

>

I'd rather have compiler throw errors rather than having yet another potential segfault in application which needs to be checked.

In that case compilation of 99% of D programs on Unix has to fail immediately. Because, potentially, they can all segfault before even reaching _Dmain. Only those that don't in any way link to C runtime may compile freely.

Sound silly enough?

November 09, 2021
On 09.11.21 16:30, Stanislav Blinov wrote:
> I mean, we can freely instantiate null delegates, but we can't instantiate nested structs?

You can get the "null" instance:

auto foo(int x){
    struct S{ int t(){ return x; } }
    return S();
}

void main(){
    // typeof(foo(0)) s; // error
    auto s=typeof(foo(0)).init; // ok
}
November 09, 2021
On Tuesday, 9 November 2021 at 15:39:48 UTC, Timon Gehr wrote:

>> template isNothrowCopyable(To, From)
>> if (is(immutable To == immutable From))
>> {
>>      enum bool isNothrowCopyable = is(typeof((ref scope From from) nothrow { union U { auto to=To.init; } U u = U(from); }));
>> }
>
> (I don't know if that solves your problem, as I don't actually have an example where your implementation does not work.)

```d
template isNothrowCopyable(To, From = To)
if (is(immutable To == immutable From))
{
    enum bool isNothrowCopyable = is(typeof((ref scope From from) nothrow { union U { auto to=To.init; } U u = U(from); }));
}

unittest
{
    int dtors;
    struct NestedThatPasses
    {
        ~this() { ++dtors; }
    }

    struct NestedThatFails
    {
        this(return ref scope typeof(this)) nothrow {}
        ~this() { ++dtors; }
    }

    static assert(isNothrowCopyable!NestedThatPasses);
    static assert(isNothrowCopyable!NestedThatFails);
}
```
November 09, 2021
On 09.11.21 16:44, Stanislav Blinov wrote:
> On Tuesday, 9 November 2021 at 15:39:48 UTC, Timon Gehr wrote:
> 
>>> template isNothrowCopyable(To, From)
>>> if (is(immutable To == immutable From))
>>> {
>>>      enum bool isNothrowCopyable = is(typeof((ref scope From from) nothrow { union U { auto to=To.init; } U u = U(from); }));
>>> }
>>
>> (I don't know if that solves your problem, as I don't actually have an example where your implementation does not work.)
> 
> ```d
> template isNothrowCopyable(To, From = To)
> if (is(immutable To == immutable From))
> {
>      enum bool isNothrowCopyable = is(typeof((ref scope From from) nothrow { union U { auto to=To.init; } U u = U(from); }));
> }
> 
> unittest
> {
>      int dtors;
>      struct NestedThatPasses
>      {
>          ~this() { ++dtors; }
>      }
> 
>      struct NestedThatFails
>      {
>          this(return ref scope typeof(this)) nothrow {}
>          ~this() { ++dtors; }
>      }
> 
>      static assert(isNothrowCopyable!NestedThatPasses);
>      static assert(isNothrowCopyable!NestedThatFails);
> }
> ```

It indeed seems ridiculous that you can't copy a nested struct using its copy constructor. I guess one solution would be to use the frame pointer of the instance you are about to copy to call the copy constructor.

I don't think calling it with `null` is a great idea.
November 09, 2021
On Tuesday, 9 November 2021 at 15:55:14 UTC, Timon Gehr wrote:

> It indeed seems ridiculous that you can't copy a nested struct using its copy constructor. I guess one solution would be to use the frame pointer of the instance you are about to copy to call the copy constructor.
>
> I don't think calling it with `null` is a great idea.

Thing is you're not calling it with null. AFAIK, the compiler blits the context first, then calls the ctor.

Pretty much the only way to crash with nested structs is to either use a default-initialized value, or do some very unsafe things. And even then - only if you actually call methods that do access the context. Which not all of them have to do.

...and then we get to even more "interesting" unittests, where a struct contains an instance of a nested struct...
November 09, 2021
On Tuesday, 9 November 2021 at 15:55:14 UTC, Timon Gehr wrote:

> I don't think calling it with `null` is a great idea.

Oh and, of course, this type of compile-time tests aren't actually calling anything at all anyway.
November 09, 2021
On 09.11.21 16:59, Stanislav Blinov wrote:
> On Tuesday, 9 November 2021 at 15:55:14 UTC, Timon Gehr wrote:
> 
>> It indeed seems ridiculous that you can't copy a nested struct using its copy constructor. I guess one solution would be to use the frame pointer of the instance you are about to copy to call the copy constructor.
>>
>> I don't think calling it with `null` is a great idea.
> 
> Thing is you're not calling it with null. AFAIK, the compiler blits the context first, then calls the ctor.

Well, that's what it should do, but it seems what actually happens is that compilation fails instead because the compiler thinks it needs a context from somewhere else to create a new instance. This seems like a bug to me.
November 09, 2021
On 09.11.21 17:04, Stanislav Blinov wrote:
> On Tuesday, 9 November 2021 at 15:55:14 UTC, Timon Gehr wrote:
> 
>> I don't think calling it with `null` is a great idea.
> 
> Oh and, of course, this type of compile-time tests aren't actually calling anything at all anyway.

Presumably you are testing because you want to actually do it later.