Jump to page: 1 24  
Page
Thread overview
[Issue 9665] New: Structure constant members can not be initialized if have opAssign
Mar 08, 2013
Maksim Zholudev
Mar 09, 2013
Kenji Hara
Mar 09, 2013
Andrej Mitrovic
Mar 09, 2013
Kenji Hara
Mar 09, 2013
Andrej Mitrovic
Mar 09, 2013
Maksim Zholudev
Mar 09, 2013
Kenji Hara
Mar 09, 2013
Maxim Fomin
Mar 10, 2013
Kenji Hara
Mar 10, 2013
Maxim Fomin
Mar 10, 2013
Maxim Fomin
Mar 11, 2013
Kenji Hara
May 07, 2013
Kenji Hara
Oct 10, 2013
Kenji Hara
Oct 10, 2013
Max Samukha
Oct 10, 2013
Max Samukha
Oct 14, 2013
Kenji Hara
Oct 15, 2013
Walter Bright
Oct 20, 2013
Kenji Hara
March 08, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=9665

           Summary: Structure constant members can not be initialized if
                    have opAssign
           Product: D
           Version: D2
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: normal
          Priority: P2
         Component: DMD
        AssignedTo: nobody@puremagic.com
        ReportedBy: maximzms@gmail.com


--- Comment #0 from Maksim Zholudev <maximzms@gmail.com> 2013-03-08 02:49:18 PST ---
Normally constant members of a structure can be initialized in constructor. However this is not possible if they have overloading of assignment operator.

This restricts usage of complex numbers from std.complex since they are structures with opAssign.

-------------------
struct Foo1 // opAssign is a function
{
    int value;
    void opAssign(int src) { value = src; }
}

struct Foo2 // opAssign is a template
{
    int value;
    void opAssign()(int src) { value = src; }
}

struct Boo
{
    const Foo1 f1;
    const Foo2 f2;

    this(int src)
    {
        f1 = src; // Error!
        f2 = src; // Error!
    }
}

void main() {}
-------------------
test.d(20): Error: mutable method test.Foo1.opAssign is not callable using a
const object
test.d(21): Error: template test.Foo2.opAssign does not match any function
template declaration. Candidates are:
test.d(10):        test.Foo2.opAssign()(int src)
test.d(21): Error: template test.Foo2.opAssign()(int src) cannot deduce
template function from argument types !()(int)
-------------------

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


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

           What    |Removed                     |Added
----------------------------------------------------------------------------
         AssignedTo|nobody@puremagic.com        |andrei@erdani.com


--- Comment #1 from Kenji Hara <k.hara.pg@gmail.com> 2013-03-09 08:01:49 PST ---
This is unfixable problem, if I'm not mistaken.

Currently, compiler always considers opAssign operator overloading for all field "assignment" in constructor.

struct S {
   T field;
   this(...) { field = xxx; } // If T has opAssign, it is called.
}

But for non-mutable field, opAssign invocation is not legal, because it may break const correctness.

T* p;
struct T {
   void opAssign(int n) { ...; p = &this; }
}
struct S {
   immutable T field;
   this(...) { field = 1;  // invoke T.opAssign (currently not allowed)
      /* now global p holds mutable pointer to immutable T object! */
   }
}

I have no answer for this issue... So, assigned to Andrei.

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


Andrej Mitrovic <andrej.mitrovich@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |andrej.mitrovich@gmail.com


--- Comment #2 from Andrej Mitrovic <andrej.mitrovich@gmail.com> 2013-03-09 09:07:15 PST ---
(In reply to comment #1)
> This is unfixable problem, if I'm not mistaken.

What if opAssign is const/inout?

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



--- Comment #3 from Kenji Hara <k.hara.pg@gmail.com> 2013-03-09 09:14:18 PST ---
(In reply to comment #2)
> (In reply to comment #1)
> > This is unfixable problem, if I'm not mistaken.
> 
> What if opAssign is const/inout?

It would be invoked, but you cannot do any meaningful operation in it.

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



--- Comment #4 from Andrej Mitrovic <andrej.mitrovich@gmail.com> 2013-03-09 09:16:40 PST ---
(In reply to comment #3)
> (In reply to comment #2)
> > (In reply to comment #1)
> > > This is unfixable problem, if I'm not mistaken.
> > 
> > What if opAssign is const/inout?
> 
> It would be invoked, but you cannot do any meaningful operation in it.

I see. Is there any use for a const opAssign?

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


rswhite4@googlemail.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |rswhite4@googlemail.com


--- Comment #5 from rswhite4@googlemail.com 2013-03-09 09:32:56 PST ---
(In reply to comment #3)
> (In reply to comment #2)
> > (In reply to comment #1)
> > > This is unfixable problem, if I'm not mistaken.
> > 
> > What if opAssign is const/inout?
> 
> It would be invoked, but you cannot do any meaningful operation in it.

You can:

import std.stdio;
import std.c.string : memcpy;

struct Foo1 // opAssign is a function
{
   int value;
   void opAssign(int src) const {
       int* ptr = cast(int*) &this.value;
       *ptr = src;
   }
}

struct Boo
{
   const Foo1 f1;

   this(int src)
   {
       f1 = src; // Error!
   }
}

void main() {
    Boo b = Boo(42);
    writeln(b.f1.value); // prints 42
}

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



--- Comment #6 from Maksim Zholudev <maximzms@gmail.com> 2013-03-09 09:47:58 PST ---
(In reply to comment #1)
> But for non-mutable field, opAssign invocation is not legal, because it may break const correctness.
> 
> T* p;
> struct T {
>    void opAssign(int n) { ...; p = &this; }
> }
> struct S {
>    immutable T field;
>    this(...) { field = 1;  // invoke T.opAssign (currently not allowed)
>       /* now global p holds mutable pointer to immutable T object! */
>    }
> }

Is there any way to break const correctness if opAssign is pure?

If not, then changes should be allowed for pure opAssign (e.g. with implicit
cast field to mutable).

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



--- Comment #7 from Kenji Hara <k.hara.pg@gmail.com> 2013-03-09 10:29:11 PST ---
(In reply to comment #5)
[snip]

To enforce breaking type system by language users is not good at all.

When talking about language semantics, unsafe operation like cast must not appear. Language user can break type system explicitly, but compiler must not do it.

(In reply to comment #6)
> Is there any way to break const correctness if opAssign is pure?

'pure' attribute does not affect constancy.

> If not, then changes should be allowed for pure opAssign (e.g. with implicit
> cast field to mutable).

opAssign should modify its 'this' object for the meaningful operation, but mutable method cannot call on non-const object, even inside constructor. So this problem is unfixable.

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


Maxim Fomin <maxim@maxim-fomin.ru> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |maxim@maxim-fomin.ru


--- Comment #8 from Maxim Fomin <maxim@maxim-fomin.ru> 2013-03-09 11:02:57 PST ---
(In reply to comment #0)
> Normally constant members of a structure can be initialized in constructor. However this is not possible if they have overloading of assignment operator.
> 
> This restricts usage of complex numbers from std.complex since they are structures with opAssign.
> 
> <skipped>

You can do:

f2.value = src;

which doesn't require opAssign as well as doesn't scale as structure grows. This does not work either when structure has private members.

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



--- Comment #9 from Andrei Alexandrescu <andrei@erdani.com> 2013-03-09 17:42:11 PST ---
This is an insufficiency in D's design. I think we should approach this the same way as super() invocation and construction of qualified objects:

1. When a constructor is entered, the object is in a "raw" state.

2. While in this raw state, the object is not considered initialized so it can't be passed to functions etc. Its const/immutable members (be they by their own qualifier or propagated from the object) are also raw and can't be passed out.

3. This raw state lasts until super() has been called EXACTLY ONCE and each qualified field has been assigned to EXACTLY ONCE.

4. At that point the object has become "cooked" and all restrictions are lifted.

Kenji, I recall we discussed this design in the context of const and immutable constructors, and you were favorable to it. How about we extend the same design for initializing qualified members in all contexts?

We can reuse the same primitive flow analysis that's now used for super().

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