www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 13872] New: std.container.Array inconsistent/misleading

https://issues.dlang.org/show_bug.cgi?id=13872

          Issue ID: 13872
           Summary: std.container.Array inconsistent/misleading reference
                    semantics for Array.init and make!Array(..)
           Product: D
           Version: D2
          Hardware: x86_64
                OS: Linux
            Status: NEW
          Severity: enhancement
          Priority: P1
         Component: Phobos
          Assignee: nobody puremagic.com
          Reporter: tobias pankrath.net

std.container.Array has reference semantics. Array.init basically is a null
reference, but it's not an error to use it since it will initialize itself
behind your back. However if you assign this reference somewhere it still
behaves like null in the sense that you get two references to two conceptually
distinct Arrays:

---------
void main()
{
    import std.container, std.stdio;
    {
        /// Example 1
        writeln("Example 1");
        // to create an empty array, you can use Array.init
        Array!int array1;
        array1.insertBack(0);

        // since Array offers reference semantics, you can make use of them
        auto refTo1 = array1;
        refTo1.insertBack(1);

        // so this prints [0, 1], as expected
        writeln(array1[]);
    }
    {
        /// Example 2
        writeln("\nExample 2");

        // however that only works if you triggered array1 to be initialized,
        // before assigning to refTo1

        // create an empty array
        Array!int array1;
        // get a second reference to it, before doing anything meaningful
        auto refTo1 = array1;

        // and fill it now
        array1.insertBack(0);
        refTo1.insertBack(1);

        // does not work as expected
        // prints array1: [0]\nrefTo1: [1] instead of 
        // array1: [0, 1]\nrefTo1: [0, 1] 
        writefln("array1: %s", array1[]);
        writefln("refTo1: %s", refTo1[]);
    }
}
---

While I do think that using Array.init should assert, I do recognize that we
probably cannot change this anymore. This should work though if I use
make!Array to construct the arrays, but does not:

---
{
        /// Example 1
        writeln("Example 1");
        // to create an empty array, you could use make as well
        Array!int array1 = make!(Array!int);
        array1.insertBack(0);

        // since Array offers reference semantics, you can make use of them
        auto refTo1 = array1;
        refTo1.insertBack(1);

        // so this prints [0, 1], as expected
        writeln(array1[]);
    }
    {
        /// Example 2
        writeln("\nExample 2");

        // however that only works if you triggered array1 to be initialized,
        // before assigning to refTo1

        // create an empty array
        Array!int array1 = make!(Array!int);
        // get a second reference to it, before doing anything meaningful
        auto refTo1 = array1;

        // and fill it now
        array1.insertBack(0);
        refTo1.insertBack(1);

        // does not work as expected
        // prints array1: [0]\nrefTo1: [1] instead of
        // array1: [0, 1]\nrefTo1: [0, 1]
        writefln("array1: %s", array1[]);
        writefln("refTo1: %s", refTo1[]);
    }
---

make(Container) should return an empty array, not the equivalent of a null
reference. This is inconsistent to class based containers as well, where make
returns a 'newed' container.

This would be an easy fix to make if we had a consistent way to force a struct
based container to become initialized. Inserting and removing an element is
ugly. In case of std.container.Array we could explicitly set length to 0, but
thats undocumented behaviour.

--
Dec 17 2014