Thread overview
Avoid initializing a struct field.
May 04, 2013
jerro
May 04, 2013
bearophile
May 04, 2013
jerro
May 05, 2013
Marco Leise
May 06, 2013
jerro
May 04, 2013
Is there a way to avoid default initializing a struct field in D? The following doesn't seem to work:

struct Foo
{
    int[42] buffer = void;
    int bar;
}

I know I can do this:

Foo foo = void

But then all fields are uninitialized.
May 04, 2013
On Saturday, 4 May 2013 at 18:11:03 UTC, jerro wrote:
> Is there a way to avoid default initializing a struct field in D? The following doesn't seem to work:
>
> struct Foo
> {
>     int[42] buffer = void;
>     int bar;
> }

I think it's supposed to work. If it doesn't work, then I think it's a compiler bug.

What code have you used to test it, and what is the result you have seen?

With this code:

struct Foo {
    int[42] buffer;
    int bar;
}
int main() {
    Foo f;
    return f.bar;
}


DMD gives this code if I use void and if I don't use it:


// With void:
Dmain:
    sub ESP, 0ACh
    mov ECX, 02Bh
    push ESI
    mov ESI, offset FLAT:_D4temp3Foo6__initZ
    push EDI
    lea EDI, 8[ESP]
    rep
    movsd
    mov EAX, 0B0h[ESP]
    pop EDI
    pop ESI
    add ESP, 0ACh
    ret


// Without void:
Dmain:
    sub ESP, 0ACh
    mov ECX, 02Bh
    xor EAX, EAX
    push EDI
    lea EDI, 4[ESP]
    rep
    stosd
    mov EAX, 0ACh[ESP]
    pop EDI
    add ESP, 0ACh
    ret


Bye,
bearophile
May 04, 2013
> What code have you used to test it, and what is the result you have seen?

I was using this code:

extern(C) void foo(Foo* r)
{
    Foo tmp;
    *r = tmp;
}

And here is the generated assembly (when using "= void"):

push   %rbp
mov    %rsp,%rbp
sub    $0xc0,%rsp
mov    %rdi,-0x10(%rbp)
movabs $0x65a360,%rsi

lea    -0xc0(%rbp),%rdi
mov    $0x15,%ecx
rep    movsq %ds:(%rsi),%es:(%rdi)
movsb  %ds:(%rsi),%es:(%rdi)
movsb  %ds:(%rsi),%es:(%rdi)
movsb  %ds:(%rsi),%es:(%rdi)
movsb  %ds:(%rsi),%es:(%rdi)
lea    -0xc0(%rbp),%rsi
mov    -0x10(%rbp),%rdi
mov    $0x15,%cl
rep    movsq %ds:(%rsi),%es:(%rdi)
movsb  %ds:(%rsi),%es:(%rdi)
movsb  %ds:(%rsi),%es:(%rdi)
movsb  %ds:(%rsi),%es:(%rdi)
movsb  %ds:(%rsi),%es:(%rdi)
leaveq
retq

The problem here is that the code copies the entire object from some static address instead of just the fields that need to be initialized, and that can be a performance problem. The same is true for your void version.

I tried using float[42] instead of int[42] and found out that buffer actually isn't initialized to its default initializer if I use "= void" (the numbers were all 0 instead of NaN), but the performance cost is still there.
May 05, 2013
Am Sat, 04 May 2013 21:00:17 +0200
schrieb "jerro" <a@a.com>:

> I tried using float[42] instead of int[42] and found out that buffer actually isn't initialized to its default initializer if I use "= void" (the numbers were all 0 instead of NaN), but the performance cost is still there.

Zero is the magic number. A struct with only binary zeros goes
to the BS section in the executable (on Windows*), taking up no
file space. So it serves a purpose as is. The .init property
is a key part of the language. It is used in equality
comparisons as well as a template that you can create carbon
copies of. "T.init" might be the default value for a parameter
of templated function, or it could be used as the initial
value for new entries in a list/table with code relying on it
being a constant.
Your point is valid to some extent, but while logical it adds
complexity and increases the odds that someone doesn't
expect .init to be a _random_ value. Because that's what it is
to templated code that is instantiated with such a struct.

*) http://d.puremagic.com/issues/show_bug.cgi?id=7319

-- 
Marco

May 06, 2013
On Sat, 04 May 2013 14:11:02 -0400, jerro <a@a.com> wrote:

> Is there a way to avoid default initializing a struct field in D? The following doesn't seem to work:
>
> struct Foo
> {
>      int[42] buffer = void;
>      int bar;
> }
>
> I know I can do this:
>
> Foo foo = void
>
> But then all fields are uninitialized.

Foo.init must exist, and be filled with *something*.  Is it useful to FORCE buffer to not have 0 values?  Or is it that you don't care what it has?  In the latter, is it terrible that it's 0?

I tend to think that without the bar there, it could potentially be uninitialized (not sure if this is the case).  But as long as it's there, buffer must also be initialized.

-Steve
May 06, 2013
On Monday, 6 May 2013 at 15:15:47 UTC, Steven Schveighoffer wrote:
> On Sat, 04 May 2013 14:11:02 -0400, jerro <a@a.com> wrote:
>
>> Is there a way to avoid default initializing a struct field in D? The following doesn't seem to work:
>>
>> struct Foo
>> {
>>     int[42] buffer = void;
>>     int bar;
>> }
>>
>> I know I can do this:
>>
>> Foo foo = void
>>
>> But then all fields are uninitialized.
>
> Foo.init must exist, and be filled with *something*.  Is it useful to FORCE buffer to not have 0 values?  Or is it that you don't care what it has?  In the latter, is it terrible that it's 0?

I don't care what it contains, I just want to avoid
initialization for performance reasons. I have something like
this:

struct Foo(size_t maxNItems)
{
     Item[maxNItems] buffer;
     size_t nItems;
     size_t addItem(...){ ... }
     void processItems(...){...}
}

The user of Foo can add up to maxNItems items and then run some
algorithm on them. Now say that Foo needs to support up to, say,
a thousand items, but in most cases just a few of them will be
added. In this case default initialization can take way more time
than the actual algorithm.
May 06, 2013
On Mon, 06 May 2013 15:01:42 -0400, jerro <a@a.com> wrote:

> On Monday, 6 May 2013 at 15:15:47 UTC, Steven Schveighoffer wrote:

>> Foo.init must exist, and be filled with *something*.  Is it useful to FORCE buffer to not have 0 values?  Or is it that you don't care what it has?  In the latter, is it terrible that it's 0?
>
> I don't care what it contains, I just want to avoid
> initialization for performance reasons.

The issue is that bar int in there.  The compiler does not generate initialization code that sets up specific members.  It basically has an init value, and it memcpy's that thing onto any uninitialized struct.

If you want performance, initialize the memory (all of it) yourself.  You can't do any worse :)

-Steve