Jump to page: 1 2
Thread overview
Member function increases size of a struct defined in a function - is this a bug?
Feb 07, 2020
Ferdinand Majerech
Feb 07, 2020
Ferdinand Majerech
Feb 07, 2020
Max Samukha
Feb 07, 2020
H. S. Teoh
Feb 07, 2020
Max Samukha
Feb 07, 2020
Max Samukha
Feb 11, 2020
Max Samukha
Feb 11, 2020
Dennis
Feb 11, 2020
Max Samukha
February 07, 2020
Ran into this while playing around with std.bitmanip.bitfields for packet protocol fields.

```
void fun()
{
    struct InnerFun
    {
        ubyte a;
        void fun() {}
    }
    struct InnerNoFun
    {
        ubyte a;
    }
    pragma(msg, "InnerFun ",   InnerFun.sizeof);  // prints 16
    pragma(msg, "InnerNoFun ", InnerNoFun.sizeof); // prints 1
}
```

Size of InnerFun is 16 while size of InnerNoFun is 1 - this took a while to debug as I could not figure out why my protocol headers are unexpectedly large - `align(1)` did not help.

This does not happen if the structs are defined outside of a function.

Is this the result of some D feature?
I can imagine this could happen if InnerFun had a silently added context pointer, but I don't know of such a feature in D.


Reported here:
https://issues.dlang.org/show_bug.cgi?id=20564
remove if this is expected behavior.
February 07, 2020
On Friday, 7 February 2020 at 12:36:23 UTC, Ferdinand Majerech wrote:
> Ran into this while playing around with std.bitmanip.bitfields for packet protocol fields.
>
> [...]

Never mind, got a reply on bugzilla (https://issues.dlang.org/show_bug.cgi?id=20564), this is a known issue.
February 07, 2020
On Friday, 7 February 2020 at 12:36:23 UTC, Ferdinand Majerech wrote:

>
> Is this the result of some D feature?
> I can imagine this could happen if InnerFun had a silently added context pointer, but I don't know of such a feature in D.
>

A pointer to the environment is a added to InnerFun for some reason (probably, a bug). You can work around by marking InnerFun 'static':

void fun()
{
    static struct InnerFun
    {
        ubyte a;
        void fun() {}
    }
    ...
}
February 07, 2020
On Fri, Feb 07, 2020 at 12:50:11PM +0000, Max Samukha via Digitalmars-d wrote:
> On Friday, 7 February 2020 at 12:36:23 UTC, Ferdinand Majerech wrote:
> > 
> > Is this the result of some D feature?
> > I can imagine this could happen if InnerFun had a silently added
> > context pointer, but I don't know of such a feature in D.
> > 
> 
> A pointer to the environment is a added to InnerFun for some reason
> (probably, a bug).

It's not a bug; the struct is declared inside function scope, and so member functions can access function local variables. Therefore a context pointer is necessary.


> You can work around by marking InnerFun 'static':
[...]

Yes, this disables access to function local variables from inside the struct, so it eliminates the context pointer.


T

-- 
To provoke is to call someone stupid; to argue is to call each other stupid.
February 07, 2020
On Friday, 7 February 2020 at 18:58:54 UTC, H. S. Teoh wrote:
> On Fri, Feb 07, 2020 at 12:50:11PM +0000, Max Samukha via Digitalmars-d wrote:
>> On Friday, 7 February 2020 at 12:36:23 UTC, Ferdinand Majerech wrote:
>> > 
>> > Is this the result of some D feature?
>> > I can imagine this could happen if InnerFun had a silently added
>> > context pointer, but I don't know of such a feature in D.
>> > 
>> 
>> A pointer to the environment is a added to InnerFun for some reason
>> (probably, a bug).
>
> It's not a bug; the struct is declared inside function scope, and so member functions can access function local variables. Therefore a context pointer is necessary.
>

It is not necessary in this case, because the member function doesn't reference any variables in the outer function.

>
>> You can work around by marking InnerFun 'static':
> [...]
>
> Yes, this disables access to function local variables from inside the struct, so it eliminates the context pointer.
>

Yes, but the compiler could infer that the context pointer is not necessary. Maybe it can't, who knows. The bug report has been open for 7 years without any response from language maintainers.

>
> T


February 07, 2020
On 2/7/20 4:31 PM, Max Samukha wrote:
> On Friday, 7 February 2020 at 18:58:54 UTC, H. S. Teoh wrote:
>> Yes, this disables access to function local variables from inside the struct, so it eliminates the context pointer.
>>
> 
> Yes, but the compiler could infer that the context pointer is not necessary. Maybe it can't, who knows. The bug report has been open for 7 years without any response from language maintainers.

There are some cases in D which *could* be done with enough analysis, but aren't because it would complicate the compiler for little benefit (or make the language dependent on how clever the compiler is).

This is one of those cases. Just add static to the struct declaration.

-Steve
February 07, 2020
On Friday, 7 February 2020 at 21:38:52 UTC, Steven Schveighoffer wrote:

>
> There are some cases in D which *could* be done with enough analysis, but aren't because it would complicate the compiler for little benefit (or make the language dependent on how clever the compiler is).
>
> This is one of those cases. Just add static to the struct declaration.
>
> -Steve

What analysis? Doesn't compiler already know the set of variables in the closure environment?
February 07, 2020
On 2/7/20 5:27 PM, Max Samukha wrote:
> On Friday, 7 February 2020 at 21:38:52 UTC, Steven Schveighoffer wrote:
> 
>>
>> There are some cases in D which *could* be done with enough analysis, but aren't because it would complicate the compiler for little benefit (or make the language dependent on how clever the compiler is).
>>
>> This is one of those cases. Just add static to the struct declaration.
>>
> 
> What analysis? Doesn't compiler already know the set of variables in the closure environment?

Yeah true. It would have to, while compiling the struct functions, add references to the closure, which means it would know if any exists by the time it's done compiling the struct functions.

However, it might need to know that before compiling.

It could really be based on how the compilation is implemented, making it difficult to figure this out.

The "add a closure reference if there are any functions" seems like a really easy thing to just do and not worry about it. And honestly, just putting static in front of the struct is also easy.

-Steve
February 11, 2020
On Friday, 7 February 2020 at 22:41:25 UTC, Steven Schveighoffer wrote:

> However, it might need to know that before compiling.
>
> It could really be based on how the compilation is implemented, making it difficult to figure this out.
>
> The "add a closure reference if there are any functions" seems like a really easy thing to just do and not worry about it. And honestly, just putting static in front of the struct is also easy.
>
> -Steve

Sorry for the late reply. I agree it is not a big issue. On the other hand, to draw an (probably far-fetched) analogy with C++ structs, I would be surprised if the compiler added a vtable pointer to the struct in the absence of virtual functions.
February 11, 2020
On Tuesday, 11 February 2020 at 11:32:47 UTC, Max Samukha wrote:
> Sorry for the late reply. I agree it is not a big issue. On the other hand, to draw an (probably far-fetched) analogy with C++ structs, I would be surprised if the compiler added a vtable pointer to the struct in the absence of virtual functions.

The thing is, because of D's static introspection and order-independent declarations things can get very complicated very quick. Here is an example that can be compiled two ways:

```
import std;

void main() {
    string str = "from closure";

    struct S {
        int b;

        string method() {
            static if (S.sizeof > int.sizeof) {
                return str; // current behavior
            } else {
                return "constant"; // also a valid option
            }
        }
    }
    writeln(S.init.method);
}

```

Of course you can account for paradoxical cases like this, and there are cases where the compiler already does:

```
struct S {
    int a = 3;
    static if (S.sizeof == int.sizeof) {
        int b = 3;
    }
    static if (S.sizeof == int.sizeof) {
        int c = 3;
    }
}
```

> variable onlineapp.S.c cannot be further field because it will change the determined S size

But the takeaway is: even if you make a decision a bit more intelligently, it can increase compiler complexity in unexpected ways.
« First   ‹ Prev
1 2