Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Returning by reference from struct method in D

I’m starting my journey in D from C++. In C++ passing by reference or value is quite explicit, but in D it seems to vary between structs and classes.

My question is how can I force a return by reference?

I have a simple XmlNode class for building Xml trees (which is a lift from my C++ code):

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

import std.stdio; 

struct XmlNode
{
    string _name;
    string _data;
    XmlNode[] _children;

    this(string name, string data="")
    {
        _name = name;
        _data = data;
    }
    
    //Trying to return a reference to the added Node
    ref XmlNode addChild(string name,string data = "")
    {
        _children ~= XmlNode(name,data);
        return _children[$-1]; 
    }

    string toString(bool bPlain = true, string indent = "")
    {
        //Omitted for brevity
    }
}

And here is the testing code:

int main()
{
    auto root = XmlNode("root");
    
    //Chained call
    root.addChild("Level 1").addChild("Level 2","42");

    //Call in two parts
    auto n = root.addChild("Level 1");
    n.addChild("Level 2","101"); //n seems to be a copy not a reference

    //Chained call
    root.addChild("Level 1").addChild("Level 2","999");

    writeln(root.toString(false));

    return 0;
}

which gives the following output:

root
  Level 1
    Level 2
      42
  Level 1
  Level 1
    Level 2
      999

As you can see the ‘chained’ use of addChild() performs as hoped. But if I try to break it up into two separate calls, only the first has an effect, and the second seems to operate on a copy of the first, not a reference. I optimistically added a ref qualifier to the addChild() signature, but that doesn’t seem to help.

As ever, I’d be grateful for any advice (using DMD / Visual D / Visual Studio / Windows 10).

>Solution :

    auto n = root.addChild("Level 1");

Here, though addChild returns a reference, it is assigned to a variable, and thus dereferenced and copied. Instead, you probably want:

    auto n = &root.addChild("Level 1");

Note that D does not have reference variables, like in C++. Variables can be only pointers (though it’s possible to write a wrapper template with reference-like semantics).

Also note that in the current design of XmlNode, the returned reference will only be valid until the next time _children is modified (as that may cause a reallocation and thus move the contents to another address, making any extant references outdated). It is a common footgun, which could be avoided by storing references of XmlNode (or making it a reference type i.e. a class), at the cost of extra dereferences and allocations.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading