Jump to page: 1 2
Thread overview
[Issue 11343] New: Error: multiple field initialization
[Issue 11343] [2.064 beta] Error: multiple field initialization
Oct 25, 2013
Kenji Hara
Oct 25, 2013
Kenji Hara
Oct 25, 2013
Kenji Hara
Oct 25, 2013
Kenji Hara
Oct 30, 2013
Kenji Hara
Oct 30, 2013
Kenji Hara
Oct 30, 2013
Kenji Hara
Oct 30, 2013
Kenji Hara
October 24, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=11343

           Summary: Error: multiple field initialization
           Product: D
           Version: D2
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: regression
          Priority: P2
         Component: DMD
        AssignedTo: nobody@puremagic.com
        ReportedBy: rswhite4@googlemail.com


--- Comment #0 from rswhite4@googlemail.com 2013-10-24 12:56:06 PDT ---
Code:
----
import std.stdio;

enum Foo {
    A = 1,
    B = 2
}

struct Test {
public:
    const ubyte[Foo] test;

    this(Foo f) {
        if (Foo.A & f)
            this.test[Foo.A] = 1;
        if (Foo.B & f)
            this.test[Foo.B] = 2;
    }
}

void main() {
    Test t = Test(Foo.A);
}
----

Flag_TEst.d(16): Error: multiple field test initialization

Tested with the latest beta.
Worked in 2.063.2

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
October 24, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=11343



--- Comment #1 from rswhite4@googlemail.com 2013-10-24 14:02:05 PDT ---
Consider also this:

----
import std.stdio;

struct Test {
public:
    const int[] test;

    this(int i) {
        this.test ~= i;
        this.test ~= i + 1;
    }
}

void main() {
    Test t = Test(42);
}
----

Same error

And maybe related: http://forum.dlang.org/thread/bug-11346-3@http.d.puremagic.com%2Fissues%2F

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
October 25, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=11343



--- Comment #2 from Kenji Hara <k.hara.pg@gmail.com> 2013-10-24 17:18:06 PDT ---
(In reply to comment #0)
> Code:
> ----
> import std.stdio;
> 
> enum Foo {
>     A = 1,
>     B = 2
> }
> 
> struct Test {
> public:
>     const ubyte[Foo] test;
> 
>     this(Foo f) {
>         if (Foo.A & f)
>             this.test[Foo.A] = 1;
>         if (Foo.B & f)
>             this.test[Foo.B] = 2;
>     }
> }
> 
> void main() {
>     Test t = Test(Foo.A);
> }
> ----
> 
> Flag_TEst.d(16): Error: multiple field test initialization
> 
> Tested with the latest beta.
> Worked in 2.063.2

It's intended behavior change introduced by fixing bug 9665. Non-mutable field initialization is now allowed just only once.

So, in this case, you need to create a temporary mutable AA, then initialize Test.test by that.

struct Test {
public:
    const ubyte[Foo] test;

    this(Foo f) {
        ubyte[Foo] tmp;
        if (Foo.A & f)
            tmp[Foo.A] = 1;
        if (Foo.B & f)
            tmp[Foo.B] = 2;
        this.test = tmp;
    }
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
October 25, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=11343



--- Comment #3 from Kenji Hara <k.hara.pg@gmail.com> 2013-10-24 17:22:40 PDT ---
(In reply to comment #1)
> Consider also this:
> 
> ----
> import std.stdio;
> 
> struct Test {
> public:
>     const int[] test;
> 
>     this(int i) {
>         this.test ~= i;
>         this.test ~= i + 1;
>     }
> }
> 
> void main() {
>     Test t = Test(42);
> }
> ----
> 
> Same error

The code modifies a non-mutable array field 'const(int[]) test' twice. Create temporary int[] and initialize Test.test by that.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
October 25, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=11343



--- Comment #4 from rswhite4@googlemail.com 2013-10-25 00:01:24 PDT ---
After my imagination, a constant member can be assigned as many times as I want, as long as it happens in the constructor. This is only logical. Everything else just makes it complex and completely non intuitive, especially for newbies.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
October 25, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=11343



--- Comment #5 from Kenji Hara <k.hara.pg@gmail.com> 2013-10-25 00:52:00 PDT ---
(In reply to comment #4)
> After my imagination, a constant member can be assigned as many times as I want, as long as it happens in the constructor. This is only logical. Everything else just makes it complex and completely non intuitive, especially for newbies.

A const reference may refer immutable data which comes from the out of the constructor. If so, modifying const data inside constructor is definitely illegal operation. By disallowing multiple initialization, compiler can validate the field initializing correctness or not, at the first initializing place.

====

Additionally, it is necessary to make immutable field data initialization more
flexible.
Today, if a pure function returns mutable data, it could be implicitly
convertible to immutable data.

    int[] make(int n) pure {
        int[] a = new int[](n);
        foreach (i; 0 .. n)
            a[i] = i + 1;
        return a;   // [1, 2, ..., n]
    }
    immutable int[] arr = make(n);  // OK

From 2.064, by fixing issue 9665, compiler can detect the only once
initializing point for the object fields.
Combine pure function, you can initialize immutable data field as follows.

struct S
{
    immutable int[] arr;

    this(int n)
    {
        static int[] make(int n) pure {
            int[] a = new int[](n);
            foreach (i; 0 .. n)
                a[i] = i + 1;
            return a;   // [1, 2, ..., n]
        }
        arr = make(n);
        // This line is now initialization (not assignment), so
        // conversion from mutable to immutable is allowed
    }
}
void main()
{
    auto s = S(10);
    assert(s.arr[0] == 0);
    assert(s.arr[$-1] == 10);
    static assert(is(typeof(s.arr) == immutable int[]));
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
October 25, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=11343


Kenji Hara <k.hara.pg@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|                            |INVALID


--- Comment #6 from Kenji Hara <k.hara.pg@gmail.com> 2013-10-25 02:08:50 PDT ---
Mark as invalid, as same as bug 11346.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
October 28, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=11343


bearophile_hugs@eml.cc changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |bearophile_hugs@eml.cc


--- Comment #7 from bearophile_hugs@eml.cc 2013-10-28 15:19:49 PDT ---
(In reply to comment #5)

> A const reference may refer immutable data which comes from the out of the constructor. If so, modifying const data inside constructor is definitely illegal operation. By disallowing multiple initialization, compiler can validate the field initializing correctness or not, at the first initializing place.

To reduce a little the disruption of formerly compilable code is it possible and a good idea to make the detector smarter, and allow code like this?

struct Foo {
    immutable int[3] arr;
    this(int x) {
        arr[0] = x;
        arr[1] = x + 1;
        arr[2] = x + 2;
    }
}
void main() {
    auto f = Foo(5);
}


Currently it gives:

test.d(5): Error: multiple field arr initialization
test.d(6): Error: multiple field arr initialization

The idea is to see and track every cell of a fixed-size array as an independent variable, like this, that compiles:


struct Foo {
    immutable int arr0, arr1, arr2;
    this(int x) {
        arr0 = x;
        arr1 = x + 1;
        arr2 = x + 2;
    }
}
void main() {
    auto f = Foo(5);
}


If this is possible and good, then I could open an enhancement request on this.

(Once that's possible, in future we could even allow some simple forms of initialization in loops, but that's for later).

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
October 30, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=11343



--- Comment #8 from Kenji Hara <k.hara.pg@gmail.com> 2013-10-29 18:51:45 PDT ---
(In reply to comment #7)
> To reduce a little the disruption of formerly compilable code is it possible and a good idea to make the detector smarter, and allow code like this?
> 
> struct Foo {
>     immutable int[3] arr;
>     this(int x) {
>         arr[0] = x;
>         arr[1] = x + 1;
>         arr[2] = x + 2;
>     }
> }

I think this is difficult if one of the index is given in runtime. For example:

    this(int x, size_t i) {
        arr[0] = x;
        arr[1] = x + 1;
        arr[i] = x + 2;  // which index will be initialized in runtime?
    }

Once arr[i] is used inside constructor, compiler should reject *all other* initializing of arr (arr[0]=x; and arr[1]=x+1;) to avoid multiple initialization. I think there's not benefits commensurate with the cost to implement it. So I won't work for that.

Instead, I'd like to recommend an alternative way how to initialize immutable int[3] field. Today, NRVO also works for static array data, and you can convert mutable data to immutable implicitly by using pure *creator* function.

    this(int x) {
        static int[3] make(int x) pure {
            int[3] a;
            a[0] = x;
            a[1] = x + 1;
            a[2] = x + 2;
        }
        this.arr = make(x);  // NRVO works
    }

In near the future, you will be able to use a pure lambda instead of the static 'make' function.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
October 30, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=11343



--- Comment #9 from rswhite4@googlemail.com 2013-10-30 01:24:58 PDT ---
This is annoying. If I want to initialize an const array I must write a new function? No way. The easier way (and I'm sure the most users will do this) is to get rid of const. That change may guarantee more safety but it will also lead that const is used less.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
« First   ‹ Prev
1 2