Thread overview
User defined types: Problems with ref
Jan 23, 2014
Chris
Jan 23, 2014
Chris
Jan 24, 2014
Ali Çehreli
Jan 24, 2014
Chris
Jan 24, 2014
Chris
Jan 23, 2014
FreeSlave
Jan 23, 2014
Chris
Jan 24, 2014
FreeSlave
Jan 24, 2014
FreeSlave
January 23, 2014
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?


January 23, 2014
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");
January 23, 2014
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.
January 23, 2014
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>
]
January 24, 2014
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.
January 24, 2014
Anyway, why do you need pointers to elements?
January 24, 2014
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

January 24, 2014
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.
January 24, 2014
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>
]