www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - std.algorithm move() struct emptying

reply Torarin <torarind gmail.com> writes:
--0016e6dd966af03282048ef947ba
Content-Type: text/plain; charset=ISO-8859-1

Hi,
in std.algorithm move(), this is the operation used to set the source of a
struct move to .init:

  static T empty;
  memcpy(&source, &empty, T.sizeof);

Is there any particular reason why the more compact &T.init is not used?

--0016e6dd966af03282048ef947ba
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

Hi,<div>in std.algorithm move(), this is the operation used to set the sour=
ce of a struct move to .init:</div><div><br></div><div><div>=A0=A0static T =
empty;</div><div>=A0=A0memcpy(&amp;source, &amp;empty, T.sizeof);</div></di=
v><div>
<br></div><div>Is there any particular reason why the more compact &amp;T.i=
nit is not used?</div><div><br></div>

--0016e6dd966af03282048ef947ba--
Aug 29 2010
next sibling parent Stanislav Blinov <stanislav.blinov gmail.com> writes:
Torarin wrote:
 Hi,
 in std.algorithm move(), this is the operation used to set the source of 
 a struct move to .init:
 
   static T empty;
   memcpy(&source, &empty, T.sizeof);
 
 Is there any particular reason why the more compact &T.init is not used?
 

I may be wrong, but it seems that in this case T.init will yield a temporary, while static T empty is 'always' there. Consider: struct S {} void main() { writefln("%x", &S.init); // prints one value writefln("%x", &S.init); // prints another value static S s; writefln("%x", &s); // prints one value writefln("%x", &s); // prints the same value }
Aug 29 2010
prev sibling next sibling parent Torarin <torarind gmail.com> writes:
Yes, you are right!
Looking at the assembly, T.init creates a struct on the stack.

2010/8/29 Stanislav Blinov <stanislav.blinov gmail.com>
 Torarin wrote:
 Hi,
 in std.algorithm move(), this is the operation used to set the source of=


 =A0static T empty;
 =A0memcpy(&source, &empty, T.sizeof);

 Is there any particular reason why the more compact &T.init is not used?

I may be wrong, but it seems that in this case T.init will yield a tempor=

 Consider:

 struct S {}

 void main()
 {
 =A0 =A0 =A0 =A0writefln("%x", &S.init); // prints one value
 =A0 =A0 =A0 =A0writefln("%x", &S.init); // prints another value

 =A0 =A0 =A0 =A0static S s;

 =A0 =A0 =A0 =A0writefln("%x", &s); // prints one value
 =A0 =A0 =A0 =A0writefln("%x", &s); // prints the same value
 }

Aug 29 2010
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 08/29/2010 12:00 PM, Torarin wrote:
 Hi,
 in std.algorithm move(), this is the operation used to set the source of
 a struct move to .init:

    static T empty;
    memcpy(&source, &empty, T.sizeof);

 Is there any particular reason why the more compact &T.init is not used?

T.init is not guaranteed to be an lvalue. Andrei
Aug 29 2010
parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
Torarin wrote:

 T.init cannot be set. It's a fixed value. When you use it, you're 


 to be copying it to an lvalue or creating a temporary. Temporaries 


 lvalues. So, T.init can be assigned to an lvalue, but it isn't 


 - Jonathan M Davis


 Currently you can take its address, so doesn't that mean that it's an lvalue?

No, you can't. Generally, that is. For example: enum A { a, b } void main() { void* p = &A.init; // won't compile } You may be able to take address of what .init returns, but what Andrei meant by 'it is not guaranteed' means that this is not always the case. So basically, you should not rely on the cases when you can do that. That's why I was wrong, also. The case wasn't about temporaries at all :)
Aug 30 2010
parent Stanislav Blinov <blinov loniir.ru> writes:
   31.08.2010 0:27, Torarin wrote:
 Yeah, I get the enum case, but what I forgot to mention is that the
 example from move() is enclosed in
 static if (is(T == struct))

 Which makes me wonder what kind of struct would have an rvalue .init.

Aug 31 2010
prev sibling next sibling parent Torarin <torarind gmail.com> writes:
Even in this case, or in some special case?

Torarin

2010/8/29 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>:
 On 08/29/2010 12:00 PM, Torarin wrote:
 Hi,
 in std.algorithm move(), this is the operation used to set the source of
 a struct move to .init:

 =A0 static T empty;
 =A0 memcpy(&source, &empty, T.sizeof);

 Is there any particular reason why the more compact &T.init is not used?

T.init is not guaranteed to be an lvalue. Andrei

Aug 29 2010
prev sibling next sibling parent Jonathan M Davis <jmdavisprog gmail.com> writes:
On Sunday, August 29, 2010 11:51:51 Torarin wrote:
 Even in this case, or in some special case?
 
 Torarin
 
 2010/8/29 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>:
 On 08/29/2010 12:00 PM, Torarin wrote:
 Hi,
 in std.algorithm move(), this is the operation used to set the source of
 a struct move to .init:
 
   static T empty;
   memcpy(&source, &empty, T.sizeof);
 
 Is there any particular reason why the more compact &T.init is not used?

T.init is not guaranteed to be an lvalue. Andrei


T.init cannot be set. It's a fixed value. When you use it, you're typically going to be copying it to an lvalue or creating a temporary. Temporaries aren't lvalues. So, T.init can be assigned to an lvalue, but it isn't itself an lvalue. - Jonathan M Davis
Aug 30 2010
prev sibling next sibling parent Torarin <torarind gmail.com> writes:
Currently you can take its address, so doesn't that mean that it's an lvalu=
e?

2010/8/30 Jonathan M Davis <jmdavisprog gmail.com>:
 On Sunday, August 29, 2010 11:51:51 Torarin wrote:
 Even in this case, or in some special case?

 Torarin

 2010/8/29 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>:
 On 08/29/2010 12:00 PM, Torarin wrote:
 Hi,
 in std.algorithm move(), this is the operation used to set the source=




 a struct move to .init:

 =A0 static T empty;
 =A0 memcpy(&source, &empty, T.sizeof);

 Is there any particular reason why the more compact &T.init is not us=




 T.init is not guaranteed to be an lvalue.

 Andrei


T.init cannot be set. It's a fixed value. When you use it, you're typical=

 to be copying it to an lvalue or creating a temporary. Temporaries aren't
 lvalues. So, T.init can be assigned to an lvalue, but it isn't itself an =

 - Jonathan M Davis

Aug 30 2010
prev sibling next sibling parent Torarin <torarind gmail.com> writes:
Yeah, I get the enum case, but what I forgot to mention is that the
example from move() is enclosed in
static if (is(T == struct))

Which makes me wonder what kind of struct would have an rvalue .init.

Torarin

2010/8/30 Stanislav Blinov <stanislav.blinov gmail.com>:

 You may be able to take address of what .init returns, but what Andrei meant
 by 'it is not guaranteed' means that this is not always the case. So
 basically, you should not rely on the cases when you can do that.

 That's why I was wrong, also. The case wasn't about temporaries at all :)

Aug 30 2010
prev sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
--0016e6d566b49cde23048f21126f
Content-Type: text/plain; charset=ISO-8859-1

On Tue, Aug 31, 2010 at 17:05, Andrei Alexandrescu <
SeeWebsiteForEmail erdani.org> wrote:

 On 8/31/10 7:49 CDT, Michel Fortin wrote:

 On 2010-08-31 06:16:17 -0400, bearophile <bearophileHUGS lycos.com> said:

  If in generic code T.init is not guaranteed to be an lvalue, as your
 example shows, isn't it better to disallow (turning it into a syntax
 error) &T.init in all cases?

Personally, I'd say the code should check if T.init is an lvalue using __traits(compiles, &T.init) or is(typeof(&T.init)) and avoid creating a static variable or temporary when it is. This optimization of course depends &T.init not being a syntax error.

I recall I wrote that code to avoid a compiler bug when T == Tuple!(some types). Andrei

Is that related to this bug? http://d.puremagic.com/issues/show_bug.cgi?id=4536 Philippe --0016e6d566b49cde23048f21126f Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable <div class=3D"gmail_quote">On Tue, Aug 31, 2010 at 17:05, Andrei Alexandres= cu <span dir=3D"ltr">&lt;<a href=3D"mailto:SeeWebsiteForEmail erdani.org">S= eeWebsiteForEmail erdani.org</a>&gt;</span> wrote:<br><blockquote class=3D"= gmail_quote" style=3D"margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb= (204, 204, 204); padding-left: 1ex;"> <div class=3D"im">On 8/31/10 7:49 CDT, Michel Fortin wrote:<br> <blockquote class=3D"gmail_quote" style=3D"margin: 0pt 0pt 0pt 0.8ex; borde= r-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;"> On 2010-08-31 06:16:17 -0400, bearophile &lt;<a href=3D"mailto:bearophileHU= GS lycos.com" target=3D"_blank">bearophileHUGS lycos.com</a>&gt; said:<br> <br> <blockquote class=3D"gmail_quote" style=3D"margin: 0pt 0pt 0pt 0.8ex; borde= r-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;"> If in generic code T.init is not guaranteed to be an lvalue, as your<br> example shows, isn&#39;t it better to disallow (turning it into a syntax<br=

</blockquote> <br> Personally, I&#39;d say the code should check if T.init is an lvalue using<= br> __traits(compiles, &amp;T.init) or is(typeof(&amp;T.init)) and avoid creati= ng a<br> static variable or temporary when it is. This optimization of course<br> depends &amp;T.init not being a syntax error.<br> </blockquote> <br></div> I recall I wrote that code to avoid a compiler bug when T =3D=3D Tuple!(som= e types).<br><font color=3D"#888888"> <br> Andrei<br></font></blockquote><div><br>Is that related to this bug?<br><a h= ref=3D"http://d.puremagic.com/issues/show_bug.cgi?id=3D4536">http://d.purem= agic.com/issues/show_bug.cgi?id=3D4536</a><br><br><br>Philippe<br>=A0<br></= div> </div><br> --0016e6d566b49cde23048f21126f--
Aug 31 2010