www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Structs should not contain pointers to internal data

reply Saurabh Das <saurabh.das silverleafcaps.com> writes:
Hello Learn-D,

I'm new to D from a C/C++ background. One caveat of defining structs in D
that I came across was that structs should be bit-wise relocatable and
hence should not contain pointers to internal data members.

So that essentially means that code of the form (below) is disallowed.

struct S1
{
    int x;
    int* p = &x;
}

What I'm wondering is, are references also disallowed? As in:

struct S2
{
    int x;
    ref int p = x;
}

I ask this because in C++, I have a telemetry class which publishes the
value of any member variable over TCP. I was trying to achieve similar
functionality in D and am wondering how to go about designing it.

Ideally I'd like to have:

struct Telemetry(T) ...

struct UsefulStruct
{
    int importantValue;
    auto tel1 = Telemetry!int(importantValue);
}

Essentially I'm asking whether the above is a valid construct in D.

Thanks,
Saurabh

On Mon, Jun 3, 2013 at 4:42 AM,
<digitalmars-d-learn-request puremagic.com>wrote:

 Send Digitalmars-d-learn mailing list submissions to
         digitalmars-d-learn puremagic.com

 To subscribe or unsubscribe via the World Wide Web, visit

 http://lists.puremagic.com/cgi-bin/mailman/listinfo/digitalmars-d-learn

 or, via email, send a message with subject or body 'help' to
         digitalmars-d-learn-request puremagic.com

 You can reach the person managing the list at
         digitalmars-d-learn-owner puremagic.com

 When replying, please edit your Subject line so it is more specific
 than "Re: Contents of Digitalmars-d-learn digest..."


 Today's Topics:

    1. What tool(s) do you use to build a large D project? (coredumper)
    2. Re: What tool(s) do you use to build a large D project?
       (Adam D. Ruppe)
    3. Re: UFCS for classes with opCall( ... ) (Timon Gehr)
    4. Re: until strange behavior (Jonathan M Davis)
    5. isMutable doesn't work with enum ? (Temtaime)
    6. Re: isMutable doesn't work with enum ? (Jonathan M Davis)
    7. Re: isMutable doesn't work with enum ? (bearophile)
    8. Re: isMutable doesn't work with enum ? (Temtaime)
    9. Re: isMutable doesn't work with enum ? (Temtaime)
   10. Re: isMutable doesn't work with enum ? (Jonathan M Davis)
   11. Re: isMutable doesn't work with enum ? (Jonathan M Davis)
   12. Re: until strange behavior (Jack Applegame)
   13. Re: until strange behavior (Jonathan M Davis)


 ----------------------------------------------------------------------

 Message: 1
 Date: Sun, 02 Jun 2013 21:20:38 +0200
 From: "coredumper" <me example.com>
 To: digitalmars-d-learn puremagic.com
 Subject: What tool(s) do you use to build a large D project?
 Message-ID: <etvbsbhiaukbnlxgixcy forum.dlang.org>
 Content-Type: text/plain; charset=utf-8; format=flowed; delsp=no

 Hello!

 What tool(s) do you use to build a D project? I looked at cmaked
 (and cmaked2) but both projects seem not to be under active
 development, there is also a bunch of other tools like dsss but
 all of them are an abandonware. So, if you are seriously using D,
 how do you build you projects? What is the mainstream way?


 ------------------------------

 Message: 2
 Date: Sun, 02 Jun 2013 21:26:43 +0200
 From: "Adam D. Ruppe" <destructionator gmail.com>
 To: digitalmars-d-learn puremagic.com
 Subject: Re: What tool(s) do you use to build a large D project?
 Message-ID: <qaythxlwuijhavdjhqqi forum.dlang.org>
 Content-Type: text/plain; charset=utf-8; format=flowed; delsp=no

 I just use plain old makefiles. I generally start with

 all:
      dmd *.d <flags>

 and then break it out just like I would with a C++ project when
 the need arises (actually pretty rare, this works quite well even
 for my larger stuff).


 ------------------------------

 Message: 3
 Date: Sun, 02 Jun 2013 22:48:47 +0200
 From: Timon Gehr <timon.gehr gmx.ch>
 To: digitalmars-d-learn puremagic.com
 Subject: Re: UFCS for classes with opCall( ... )
 Message-ID: <kogb3f$ehk$1 digitalmars.com>
 Content-Type: text/plain; charset=UTF-8; format=flowed

 On 06/01/2013 02:22 PM, ParticlePeter wrote:
 Hello,

 after watching Walters Talk about Component Programming ( link Bellow )
 I was quite fond of his pipelining approach.
 I tried the following and had to realize that this way using UFCS isn't
 working ( or I do something wrong ).

 // I want to write On Canvas1 | draw Shape1 | draw Shape2 | ... in code
 ( not working ):
 canvas1.shape1.shape2.draw()

 // Which in essence would be ( working ):
 shape2( shape1( canvas1 ) ).draw()
 ...
UFCS is working with opCall already. The reason your code does not work is that UFCS only works with module-level symbols (and with the latest release also for locally imported symbols IIRC.) ------------------------------ Message: 4 Date: Sun, 02 Jun 2013 13:50:15 -0700 From: Jonathan M Davis <jmdavisProg gmx.com> To: "digitalmars.D.learn" <digitalmars-d-learn puremagic.com> Subject: Re: until strange behavior Message-ID: <2641846.fA8uGAeyYA lyonel> Content-Type: text/plain; charset="utf-8" On Sunday, June 02, 2013 15:20:31 Temtaime wrote:
 Why

 char arr[3] = "abc";
 arr[].until('b').front has type of dchar ???
http://stackoverflow.com/questions/12288465 - Jonathan M Davis ------------------------------ Message: 5 Date: Mon, 03 Jun 2013 00:14:34 +0200 From: "Temtaime" <temtaime gmail.com> To: digitalmars-d-learn puremagic.com Subject: isMutable doesn't work with enum ? Message-ID: <eruaxrnxigbyqamlxemq forum.dlang.org> Content-Type: text/plain; charset=utf-8; format=flowed; delsp=no Hi! enum int a = 5; writeln(isMutable!(typeof(a))); Writes true. Why? How i can figure out if variable is "enum" constant ? Thanks. Regards. ------------------------------ Message: 6 Date: Sun, 02 Jun 2013 15:23:36 -0700 From: Jonathan M Davis <jmdavisProg gmx.com> To: "digitalmars.D.learn" <digitalmars-d-learn puremagic.com> Subject: Re: isMutable doesn't work with enum ? Message-ID: <4584128.RAFB2m748R lyonel> Content-Type: text/plain; charset="utf-8" On Monday, June 03, 2013 00:14:34 Temtaime wrote:
 Hi!

       enum int a = 5;
       writeln(isMutable!(typeof(a)));

 Writes true. Why? How i can figure out if variable is "enum"
 constant ?
 Thanks.
 Regards.
isMutable just checks whether the type const or immutable, and is true if it's neither. And int is mutable. Also, what you've declared there is a manifest constant, not really an enum in the normal sense. It would have to have a type name for it be a full-on enum. Something more like enum E : int { a = 5 } Your a there is not typed as an enum at all. The difference between it and doing something like immutable int a = 5; is the fact a manifest constant does not have an address and gets copy-pasted where it's used, which is why doing something like enum arr = [1, 2, 3, 4, 5]; is often considered a bad idea. An array gets allocated every time that the manifest constant is used, because using arr effectively just pastes [1, 2, 3, 4, 5] in its place. However, if you really want to check whether something is an enum or not, do is(E == enum) And with your original definition, is(typeof(a) == enum) will be false, because its type is int. - Jonathan M Davis ------------------------------ Message: 7 Date: Mon, 03 Jun 2013 00:30:42 +0200 From: "bearophile" <bearophileHUGS lycos.com> To: digitalmars-d-learn puremagic.com Subject: Re: isMutable doesn't work with enum ? Message-ID: <hpdebexqxrzebtgixoua forum.dlang.org> Content-Type: text/plain; charset=utf-8; format=flowed; delsp=no Temtaime:
       enum int a = 5;
       writeln(isMutable!(typeof(a)));

 Writes true. Why?
If you run this: enum int a = 5; pragma(msg, typeof(a)); void main() {} It prints "int". An int is mutable.
 How i can figure out if variable is "enum" constant ?
Why do you need to know that? Bye, bearophile ------------------------------ Message: 8 Date: Mon, 03 Jun 2013 00:34:49 +0200 From: "Temtaime" <temtaime gmail.com> To: digitalmars-d-learn puremagic.com Subject: Re: isMutable doesn't work with enum ? Message-ID: <jfpkdgmmvfsifarokmsu forum.dlang.org> Content-Type: text/plain; charset=utf-8; format=flowed; delsp=no It's intresting. So the only way to pass "a" to overloaded function like that ? void foo(T)(ref T) { writeln("true"); } void foo(T)(auto ref in T) { writeln("false"); } enum int a = 10; foo(a); // false int b = 1; foo(b); // true ------------------------------ Message: 9 Date: Mon, 03 Jun 2013 00:36:46 +0200 From: "Temtaime" <temtaime gmail.com> To: digitalmars-d-learn puremagic.com Subject: Re: isMutable doesn't work with enum ? Message-ID: <ecwvfgfajylndwlyjccu forum.dlang.org> Content-Type: text/plain; charset=utf-8; format=flowed; delsp=no I'm writing serializer and it iterates all members of struct. It compares fields marked as "enum" when reading from file to check BOM, for example. I'm using enum now because const members are deprecated in 2.063. ------------------------------ Message: 10 Date: Sun, 02 Jun 2013 15:40:32 -0700 From: Jonathan M Davis <jmdavisProg gmx.com> To: "digitalmars.D.learn" <digitalmars-d-learn puremagic.com> Subject: Re: isMutable doesn't work with enum ? Message-ID: <1713172.WrMD0SRKMg lyonel> Content-Type: text/plain; charset="utf-8" On Monday, June 03, 2013 00:34:49 Temtaime wrote:
 It's intresting.
 So the only way to pass "a" to overloaded function like that ?

 void foo(T)(ref T) { writeln("true"); }
 void foo(T)(auto ref in T) { writeln("false"); }

 enum int a = 10;
 foo(a); // false

 int b = 1;
 foo(b); // true
ref only accepts lvalues. An enum is not an lvalue. auto ref makes it so that if the templated function is passed an lvalue, it generates a ref version, whereas if it's passed an rvalue, it generates a non-ref version. It would appear that the compiler considers ref to be a better match than auto ref (as opposed to giving an error), so when you pass foo an lvalue, the ref version gets called, but when you pass it an rvalue, the only viable overload is the auto ref one, so it gets called. - Jonathan M Davis ------------------------------ Message: 11 Date: Sun, 02 Jun 2013 15:42:09 -0700 From: Jonathan M Davis <jmdavisProg gmx.com> To: "digitalmars.D.learn" <digitalmars-d-learn puremagic.com> Subject: Re: isMutable doesn't work with enum ? Message-ID: <19062665.b9QIKb6H1G lyonel> Content-Type: text/plain; charset="utf-8" On Monday, June 03, 2013 00:36:46 Temtaime wrote:
 I'm writing serializer and it iterates all members of struct.
 It compares fields marked as "enum" when reading from file to
 check BOM, for example.

 I'm using enum now because const members are deprecated in 2.063.
The equivalent to what const members were doing before is static const. static was being implicitly tacked onto the const. enums do something subtley different. static const variables are actually variables with addresses (lvalues), whereas enums have no address and are rvalues. - Jonathan M Davis ------------------------------ Message: 12 Date: Mon, 03 Jun 2013 01:04:28 +0200 From: "Jack Applegame" <japplegame gmail.com> To: digitalmars-d-learn puremagic.com Subject: Re: until strange behavior Message-ID: <qahcvglusxgrkshoocti forum.dlang.org> Content-Type: text/plain; charset=utf-8; format=flowed; delsp=no On Sunday, 2 June 2013 at 20:50:31 UTC, Jonathan M Davis wrote:
 http://stackoverflow.com/questions/12288465
Lets have string of chars, and it contains UTF-8 string. Does front(str[]) automatically convert first unicode character to UTF-32 and returns it? I made a test case and answer is: "Yes, it does!" May be this make sense. But such implicit conversion confuses everyone whom I asked. Therefore, string is not ordinary array (in Phobos context), but special array with special processing rules. I'm moving from C++ and often ask myself: "why D has so much hidden confusing things?" ------------------------------ Message: 13 Date: Sun, 02 Jun 2013 16:12:09 -0700 From: Jonathan M Davis <jmdavisProg gmx.com> To: "digitalmars.D.learn" <digitalmars-d-learn puremagic.com> Subject: Re: until strange behavior Message-ID: <10181668.aRRsJoJz5o lyonel> Content-Type: text/plain; charset="utf-8" On Monday, June 03, 2013 01:04:28 Jack Applegame wrote:
 On Sunday, 2 June 2013 at 20:50:31 UTC, Jonathan M Davis wrote:
 http://stackoverflow.com/questions/12288465
Lets have string of chars, and it contains UTF-8 string. Does front(str[]) automatically convert first unicode character to UTF-32 and returns it? I made a test case and answer is: "Yes, it does!" May be this make sense. But such implicit conversion confuses everyone whom I asked. Therefore, string is not ordinary array (in Phobos context), but special array with special processing rules. I'm moving from C++ and often ask myself: "why D has so much hidden confusing things?"
The language treats strings as arrays of code units. The standard library treats them as ranges of code points. Yes, this can be confusing, but we need both. In order to operate on strings efficiently, they need to be made up of code units, but correctness requires code points. This means that the complexity is to a great extent an intrinsic part of dealing with strings properly. In C++, people usually just screw it up and treat char as if it were a character when in fact it's not. It's a piece of one. Whether we went about handling the complexity of code units vs code points in the best manner is debatable, but it can't be made simple if you want both efficiency and correctness. A better approach might have been to have a string type which operated on code points and held the code units internally so that everything operated on code points by default, but the library stuff was added later, and Walter Bright tends to think that everyone should understand Unicode well, so the decisions he makes with regards to that aren't always the best (since most people don't understand Unicode well and don't want to care). What we have actually works quite well, but it does require that you come to at least a basic understanding of the difference between code units and code points. - Jonathan M Davis ------------------------------ _______________________________________________ Digitalmars-d-learn mailing list Digitalmars-d-learn puremagic.com http://lists.puremagic.com/cgi-bin/mailman/listinfo/digitalmars-d-learn End of Digitalmars-d-learn Digest, Vol 89, Issue 5 **************************************************
Jun 02 2013
next sibling parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 06/02/2013 09:53 PM, Saurabh Das wrote:

 structs should be bit-wise relocatable and
 hence should not contain pointers to internal data members.
That's correct. I can't find at this time what part of the spec you are quoting. :) I was wondering whether it specifically says pointer, or reference in its general meaning.
 struct Telemetry(T) ...

 struct UsefulStruct
 {
      int importantValue;
      auto tel1 = Telemetry!int(importantValue);
 }

 Essentially I'm asking whether the above is a valid construct in D.
The answer is based on the fact that struct objects can be freely relocated. Will UsefulStruct work correctly when that happens? If yes, then it is valid. Ali
Jun 02 2013
prev sibling parent reply Saurabh Das <saurabh.das silverleafcaps.com> writes:
Thank you  Ali and  Jonothan!

So essentially since I will be storing a pointer, Telemetry!(T) is NOT safe
to use only with structs in general.

If I have something like:

struct UsefulStruct2
{
    this(this)  disable;
    this(UsefulStruct2)  disable;
  this(ref const(UsefulStruct2))  disable;
  ref UsefulStruct2 opAssign(UsefulStruct2)  disable;
  ref UsefulStruct2 opAssign(ref const(UsefulStruct2))  disable;

    int importantValue;
    auto tel1 = Telemetry!int(importantValue);
}

Does that ensure that UsefulStruct2 is not relocateable and thus I can
safely store a pointer to importantValue?

If not, what constraints do I need to add to my classes to ensure that I
don't run into subtle bugs when structs relocate?

Regards,
Saurabh Das
Jun 03 2013
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 06/03/2013 05:26 AM, Saurabh Das wrote:

 Thank you  Ali and  Jonothan!

 So essentially since I will be storing a pointer, Telemetry!(T) is 
NOT safe
 to use only with structs in general.

 If I have something like:

 struct UsefulStruct2
 {
      this(this)  disable;
      this(UsefulStruct2)  disable;
    this(ref const(UsefulStruct2))  disable;
    ref UsefulStruct2 opAssign(UsefulStruct2)  disable;
    ref UsefulStruct2 opAssign(ref const(UsefulStruct2))  disable;

      int importantValue;
      auto tel1 = Telemetry!int(importantValue);
 }

 Does that ensure that UsefulStruct2 is not relocateable and thus I can
 safely store a pointer to importantValue?
No. The compiler can still move a struct by blit (bit level transfer). Blit is based on good old memcpy. For a "copy", post-blit is for making corrections after the fact. On the other hand, the programmer cannot interfere if it is a "move". For example, rvalues are moved, e.g. to an array element as in the following example: import std.stdio; import std.array; struct UsefulStruct2 { this(this) disable; this(UsefulStruct2) disable; this(ref const(UsefulStruct2)) disable; ref UsefulStruct2 opAssign(UsefulStruct2) disable; ref UsefulStruct2 opAssign(ref const(UsefulStruct2)) disable; int importantValue; int * p; } UsefulStruct2 makeObject(int i) { UsefulStruct2 u; u.importantValue = i; u.p = &u.importantValue; // <-- self-referencing return u; } void main() { auto arr = [ makeObject(1) ]; assert(arr.front.p != &arr.front.importantValue); // PASSES! }
 If not, what constraints do I need to add to my classes to ensure that I
 don't run into subtle bugs when structs relocate?
As you see, disable is cripling and not a solution for this. As far as I know, the only option is to observe this rule. I agree with you that a struct may become self-referencing, unknowingly and indirectly through members of other types. Ali
Jun 03 2013
parent "Diggory" <diggsey googlemail.com> writes:
On Monday, 3 June 2013 at 16:00:58 UTC, Ali Çehreli wrote:
 On 06/03/2013 05:26 AM, Saurabh Das wrote:

 Thank you  Ali and  Jonothan!

 So essentially since I will be storing a pointer,
Telemetry!(T) is NOT safe
 to use only with structs in general.

 If I have something like:

 struct UsefulStruct2
 {
      this(this)  disable;
      this(UsefulStruct2)  disable;
    this(ref const(UsefulStruct2))  disable;
    ref UsefulStruct2 opAssign(UsefulStruct2)  disable;
    ref UsefulStruct2 opAssign(ref const(UsefulStruct2))
disable;
      int importantValue;
      auto tel1 = Telemetry!int(importantValue);
 }

 Does that ensure that UsefulStruct2 is not relocateable and
thus I can
 safely store a pointer to importantValue?
No. The compiler can still move a struct by blit (bit level transfer). Blit is based on good old memcpy. For a "copy", post-blit is for making corrections after the fact. On the other hand, the programmer cannot interfere if it is a "move". For example, rvalues are moved, e.g. to an array element as in the following example: import std.stdio; import std.array; struct UsefulStruct2 { this(this) disable; this(UsefulStruct2) disable; this(ref const(UsefulStruct2)) disable; ref UsefulStruct2 opAssign(UsefulStruct2) disable; ref UsefulStruct2 opAssign(ref const(UsefulStruct2)) disable; int importantValue; int * p; } UsefulStruct2 makeObject(int i) { UsefulStruct2 u; u.importantValue = i; u.p = &u.importantValue; // <-- self-referencing return u; } void main() { auto arr = [ makeObject(1) ]; assert(arr.front.p != &arr.front.importantValue); // PASSES! }
 If not, what constraints do I need to add to my classes to
ensure that I
 don't run into subtle bugs when structs relocate?
As you see, disable is cripling and not a solution for this. As far as I know, the only option is to observe this rule. I agree with you that a struct may become self-referencing, unknowingly and indirectly through members of other types. Ali
You can get around this limitation by making a wrapper struct which uses special values to represent pointers which point within the containing struct, and does the conversion automatically when you dereference it.
Jun 03 2013