www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - User defined types: Problems with ref

reply "Chris" <wendlec tcd.ie> writes:
Here's what I'm trying to do.

struct Element(T) {
     T x;
     T y;

     public void setX(T value) {
       x = value;
     }
     // More fancy functions ...
}

I store Element(s) in an array and want to pass each one by 
reference, which does not work.


class Tree {

     Element!string[] elements;

     public ref auto createElement(string name) {
       elements ~= Element!string(name);
       return elements[$-1];
     }
}

in main:

auto tag = Element!string("first");

The elements in Tree.elements and the ones in main are not the 
same, instead I obtain a copy of each.
How can I make them refer to the same Elements? If I have to add 
a .ptr property to Element, how do I do that? Is that possible at 
all or did I shoot myself in the foot with the template?
Jan 23 2014
next sibling parent reply "Chris" <wendlec tcd.ie> writes:
On Thursday, 23 January 2014 at 15:24:19 UTC, Chris wrote:
 Here's what I'm trying to do.

 struct Element(T) {
     T x;
     T y;

     public void setX(T value) {
       x = value;
     }
     // More fancy functions ...
 }

 I store Element(s) in an array and want to pass each one by 
 reference, which does not work.


 class Tree {

     Element!string[] elements;

     public ref auto createElement(string name) {
       elements ~= Element!string(name);
       return elements[$-1];
     }
 }

 in main:

 auto tag = Element!string("first");

 The elements in Tree.elements and the ones in main are not the 
 same, instead I obtain a copy of each.
 How can I make them refer to the same Elements? If I have to 
 add a .ptr property to Element, how do I do that? Is that 
 possible at all or did I shoot myself in the foot with the 
 template?
Sorry in main it is: auto tree = new Tree(); auto tag = tree.createElement("first");
Jan 23 2014
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 01/23/2014 07:26 AM, Chris wrote:

 On Thursday, 23 January 2014 at 15:24:19 UTC, Chris wrote:
 Here's what I'm trying to do.

 struct Element(T) {
     T x;
     T y;

     public void setX(T value) {
       x = value;
     }
     // More fancy functions ...
 }

 I store Element(s) in an array and want to pass each one by reference,
 which does not work.


 class Tree {

     Element!string[] elements;

     public ref auto createElement(string name) {
       elements ~= Element!string(name);
       return elements[$-1];
     }
 }

 in main:

 auto tag = Element!string("first");

 The elements in Tree.elements and the ones in main are not the same,
 instead I obtain a copy of each.
 How can I make them refer to the same Elements? If I have to add a
 .ptr property to Element, how do I do that? Is that possible at all or
 did I shoot myself in the foot with the template?
Sorry in main it is: auto tree = new Tree(); auto tag = tree.createElement("first");
createElement does return a reference. However, because D does not have local references the type of tag is Element!string (not 'ref Element!string'). The following program demonstrates that the address of the returned reference is indeed the same as the one that has been created: import std.stdio; struct Element(T) { T x; T y; public void setX(T value) { x = value; } // More fancy functions ... } class Tree { Element!string[] elements; public ref auto createElement(string name) { elements ~= Element!string(name); writefln(" created element at %s", &elements[$-1]); return elements[$-1]; } } void main() { auto tree = new Tree(); writefln("received element at %s", &tree.createElement("first")); } Sample output: created element at 7F14C72C0F80 received element at 7F14C72C0F80 You can use the returned element directly as well: tree.createElement("second").setX("hello"); Ali
Jan 23 2014
parent reply "Chris" <wendlec tcd.ie> writes:
On Friday, 24 January 2014 at 01:26:06 UTC, Ali Çehreli wrote:
 On 01/23/2014 07:26 AM, Chris wrote:

 On Thursday, 23 January 2014 at 15:24:19 UTC, Chris wrote:
 Here's what I'm trying to do.

 struct Element(T) {
     T x;
     T y;

     public void setX(T value) {
       x = value;
     }
     // More fancy functions ...
 }

 I store Element(s) in an array and want to pass each one by
reference,
 which does not work.


 class Tree {

     Element!string[] elements;

     public ref auto createElement(string name) {
       elements ~= Element!string(name);
       return elements[$-1];
     }
 }

 in main:

 auto tag = Element!string("first");

 The elements in Tree.elements and the ones in main are not
the same,
 instead I obtain a copy of each.
 How can I make them refer to the same Elements? If I have to
add a
 .ptr property to Element, how do I do that? Is that possible
at all or
 did I shoot myself in the foot with the template?
Sorry in main it is: auto tree = new Tree(); auto tag = tree.createElement("first");
createElement does return a reference. However, because D does not have local references the type of tag is Element!string (not 'ref Element!string'). The following program demonstrates that the address of the returned reference is indeed the same as the one that has been created: import std.stdio; struct Element(T) { T x; T y; public void setX(T value) { x = value; } // More fancy functions ... } class Tree { Element!string[] elements; public ref auto createElement(string name) { elements ~= Element!string(name); writefln(" created element at %s", &elements[$-1]); return elements[$-1]; } } void main() { auto tree = new Tree(); writefln("received element at %s", &tree.createElement("first")); } Sample output: created element at 7F14C72C0F80 received element at 7F14C72C0F80 You can use the returned element directly as well: tree.createElement("second").setX("hello"); Ali
Thank you guys. Yes, it's the array bit that kills the reference as FreeSlave pointed out. After tinkering around with it, I've (reluctantly) turned Element into a class to get the reference semantics. I need a reference so I can do things like tree.getElementById("div"); It's a basic (very simple) HTML / markup thing. Tree stores all elements, but the elements are changed outside Tree, like so auto div = tree.createElement("div"); div.setAttribute("id", "1"); // ... div.appendChild(...); etc. I'm sure there are cleverer ways of implementing a HTML tree.
Jan 24 2014
parent "Chris" <wendlec tcd.ie> writes:
Now the output is as it should be (after changing the elements).

// The div.toString();
<div class="text" onclick="function();" id="1">
Hello, world!
<span>
I am a span
</span>
</div>

// Tree Elements
[<div class="text" onclick="function();" id="1">
Hello, world!
<span>
I am a span
</span>
</div>
, <span>
I am a span
</span>
]
Jan 24 2014
prev sibling parent reply "FreeSlave" <freeslave93 gmail.com> writes:
On Thursday, 23 January 2014 at 15:24:19 UTC, Chris wrote:
 Here's what I'm trying to do.

 struct Element(T) {
     T x;
     T y;

     public void setX(T value) {
       x = value;
     }
     // More fancy functions ...
 }

 I store Element(s) in an array and want to pass each one by 
 reference, which does not work.


 class Tree {

     Element!string[] elements;

     public ref auto createElement(string name) {
       elements ~= Element!string(name);
       return elements[$-1];
     }
 }

 in main:

 auto tag = Element!string("first");

 The elements in Tree.elements and the ones in main are not the 
 same, instead I obtain a copy of each.
 How can I make them refer to the same Elements? If I have to 
 add a .ptr property to Element, how do I do that? Is that 
 possible at all or did I shoot myself in the foot with the 
 template?
You can use pointer Tree tree = new Tree(); Element!(string)* element = &tree.createElement("first"); & is to get address of returned value element. You also can rewrite your function like this: public Element!(string)* createElement(string name) { elements ~= Element!string(name); return &elements[$-1]; } to return pointer without need to get address on caller side.
Jan 23 2014
parent reply "Chris" <wendlec tcd.ie> writes:
On Thursday, 23 January 2014 at 15:34:38 UTC, FreeSlave wrote:
 On Thursday, 23 January 2014 at 15:24:19 UTC, Chris wrote:
 Here's what I'm trying to do.

 struct Element(T) {
    T x;
    T y;

    public void setX(T value) {
      x = value;
    }
    // More fancy functions ...
 }

 I store Element(s) in an array and want to pass each one by 
 reference, which does not work.


 class Tree {

    Element!string[] elements;

    public ref auto createElement(string name) {
      elements ~= Element!string(name);
      return elements[$-1];
    }
 }

 in main:

 auto tag = Element!string("first");

 The elements in Tree.elements and the ones in main are not the 
 same, instead I obtain a copy of each.
 How can I make them refer to the same Elements? If I have to 
 add a .ptr property to Element, how do I do that? Is that 
 possible at all or did I shoot myself in the foot with the 
 template?
You can use pointer Tree tree = new Tree(); Element!(string)* element = &tree.createElement("first"); & is to get address of returned value element. You also can rewrite your function like this: public Element!(string)* createElement(string name) { elements ~= Element!string(name); return &elements[$-1]; } to return pointer without need to get address on caller side.
Thanks, that was fast! Yes I was tinkering around with pointers, but didn't get it right, you did. However, the output is still the same, i.e. two different sets: // After creating and changing <div id="1"> Hello, world! <span> </span> </div> // The Elements in Tree.elements: [<div> </div> , <span> </span> ]
Jan 23 2014
parent reply "FreeSlave" <freeslave93 gmail.com> writes:
On Thursday, 23 January 2014 at 15:24:19 UTC, Chris wrote:
 Thanks, that was fast! Yes I was tinkering around with 
 pointers, but didn't get it right, you did. However, the output 
 is still the same, i.e. two different sets:

 // After creating and changing
 <div id="1">
 Hello, world!
 <span>
 </span>
 </div>

 // The Elements in Tree.elements:
 [<div>
 </div>
 , <span>
 </span>
 ]
Maybe more code will explain more. Note that array requires data to be continuous, so if there are no space for new element, it reallocates the whole chunk and therefore invalidates old pointers. Use linked list or replace struct with class.
Jan 23 2014
parent "FreeSlave" <freeslave93 gmail.com> writes:
Anyway, why do you need pointers to elements?
Jan 23 2014