Thread overview
@nogc nothrow for Variant.peek
August 10

Hi everyone,

I'm trying to use Variant.peek structs in a @nogc nothrow code, but it seems this is not possible.

From what I see in the source code here: https://github.com/dlang/phobos/blob/master/std/variant.d#L790 there is no reason why this function would not be @nogc nothrow. Is there something that I am missing?

Thanks,
Bogdan

August 10

On 8/10/23 3:56 AM, Bogdan Szabo wrote:

>

Hi everyone,

I'm trying to use Variant.peek structs in a @nogc nothrow code, but it seems this is not possible.

From what I see in the source code here: https://github.com/dlang/phobos/blob/master/std/variant.d#L790 there is no reason why this function would not be @nogc nothrow. Is there something that I am missing?

The only "smart" operation there is the TypeInfo comparison. I don't see why it can't be @nogc and nothrow.

-Steve

August 11

On Thursday, 10 August 2023 at 07:56:07 UTC, Bogdan Szabo wrote:

>

Hi everyone,

I'm trying to use Variant.peek structs in a @nogc nothrow code, but it seems this is not possible.

From what I see in the source code here: https://github.com/dlang/phobos/blob/master/std/variant.d#L790 there is no reason why this function would not be @nogc nothrow. Is there something that I am missing?

Thanks,
Bogdan

If I put @nogc nothrow on Variant.peek and attempt to compile Phobos, DMD master gives this error message:

std/variant.d(795): Error: `@nogc` function `std.variant.VariantN!32LU.VariantN.peek!void.peek` cannot call non-@nogc function `std.variant.VariantN!32LU.VariantN.type`
std/variant.d(823):        which wasn't inferred `@nogc` because of:
std/variant.d(823):        `@nogc` function `std.variant.VariantN!32LU.VariantN.type` cannot call non-@nogc `this.fptr`
std/variant.d(795): Error: `@nogc` function `std.variant.VariantN!32LU.VariantN.peek!void.peek` cannot call non-@nogc function `object.opEquals!(TypeInfo, TypeInfo).opEquals`
../dmd/druntime/import/object.d(275):        which calls `object.TypeInfo.opEquals`

So, there are two reasons:

  1. Variant.peek calls Variant.type which calls Variant.fptr, which is not @nogc nothrow.
  2. Variant.peek calls TypeInfo.opEquals, which is not @nogc nothrow.

Reason (1) is theoretically solvable by refactoring Variant. Reason (2) would require backwards-incompatible language changes to solve (changes to TypeInfo's public interface).

August 11

On 8/11/23 10:24 AM, Paul Backus wrote:

>

On Thursday, 10 August 2023 at 07:56:07 UTC, Bogdan Szabo wrote:

>

Hi everyone,

I'm trying to use Variant.peek structs in a @nogc nothrow code, but it seems this is not possible.

From what I see in the source code here: https://github.com/dlang/phobos/blob/master/std/variant.d#L790 there is no reason why this function would not be @nogc nothrow. Is there something that I am missing?

Thanks,
Bogdan

If I put @nogc nothrow on Variant.peek and attempt to compile Phobos, DMD master gives this error message:

std/variant.d(795): Error: `@nogc` function `std.variant.VariantN!32LU.VariantN.peek!void.peek` cannot call non-@nogc function `std.variant.VariantN!32LU.VariantN.type`
std/variant.d(823):        which wasn't inferred `@nogc` because of:
std/variant.d(823):        `@nogc` function `std.variant.VariantN!32LU.VariantN.type` cannot call non-@nogc `this.fptr`
std/variant.d(795): Error: `@nogc` function `std.variant.VariantN!32LU.VariantN.peek!void.peek` cannot call non-@nogc function `object.opEquals!(TypeInfo, TypeInfo).opEquals`
../dmd/druntime/import/object.d(275):        which calls `object.TypeInfo.opEquals`

So, there are two reasons:

  1. Variant.peek calls Variant.type which calls Variant.fptr, which is not @nogc nothrow.
  2. Variant.peek calls TypeInfo.opEquals, which is not @nogc nothrow.

Reason (1) is theoretically solvable by refactoring Variant. Reason (2) would require backwards-incompatible language changes to solve (changes to TypeInfo's public interface).

You can assume TypeInfo.opEquals is nogc (all TypeInfos in this instance are compiler-generated and opEquals does not use the gc). So it would be fine to cast around that.

The "public interface" in this case is anyone making their own TypeInfo derivative. It would be fine to change TypeInfo.opEquals to @nogc as a user of it. But in this case, I think it's fine to cast away the nogc thing.

Could be the same solution with fptr, since we know that this specific call to fptr will not use the gc or throw.

-Steve

August 11

On Friday, 11 August 2023 at 14:50:25 UTC, Steven Schveighoffer wrote:

>

You can assume TypeInfo.opEquals is nogc (all TypeInfos in this instance are compiler-generated and opEquals does not use the gc). So it would be fine to cast around that.

The "public interface" in this case is anyone making their own TypeInfo derivative. It would be fine to change TypeInfo.opEquals to @nogc as a user of it. But in this case, I think it's fine to cast away the nogc thing.

Casting is an ugly solution, but in practice, yeah, you would almost certainly get away with it.

>

Could be the same solution with fptr, since we know that this specific call to fptr will not use the gc or throw.

Well, you know it doesn't in the current version of the code. But there's nothing stopping future changes from breaking that assumption.

The non-ugly way to fix this is to split handler up into separate functions, and replace fptr with a pointer to a vtable. Then each of the function pointers in the vtable can have its own set of attributes.

August 11

On 8/11/23 11:05 AM, Paul Backus wrote:

>

On Friday, 11 August 2023 at 14:50:25 UTC, Steven Schveighoffer wrote:

>

Could be the same solution with fptr, since we know that this specific call to fptr will not use the gc or throw.

Well, you know it doesn't in the current version of the code. But there's nothing stopping future changes from breaking that assumption.

The non-ugly way to fix this is to split handler up into separate functions, and replace fptr with a pointer to a vtable. Then each of the function pointers in the vtable can have its own set of attributes.

I actually find that uglier. From a performance standpoint, this probably involves a 2-level indirection (one to the vtable, and then the function call as well).

Possibly, a compromise is to factor out pieces that need specific attributes as nested functions and attribute those. At least that would silo off the pieces that need to be attributed that way, and make it more obvious if you change something that violates the attributes.

-Steve