Is this really intended??

Steven Schveighoffer schveiguy at gmail.com
Sun Oct 11 22:11:48 UTC 2020


On 10/11/20 5:50 PM, claptrap wrote:
> On Sunday, 11 October 2020 at 18:57:55 UTC, Steven Schveighoffer wrote:
>> On 10/10/20 8:16 PM, claptrap wrote:
>>> struct Foo
>>> {
>>>      int i;
>>>      void opAssign(int rhs) { this.i = rhs; }
>>>      void reset() { i = 0; }
>>> }
>>>
>>> class Bar
>>> {
>>>      Foo foo;
>>>
>>>      this()
>>>      {
>>>          foo.i = 0;    // *1
>>>          foo.reset();  // *2
>>>          foo = 42;
>>>      }
>>> }
>>>
>>> With *1 & *2 commented out...
>>>
>>> onlineapp.d(19): Error: cannot implicitly convert expression x of 
>>> type int to Foo
>>> onlineapp.d(19):        this.foo = x is the first assignment of 
>>> this.foo therefore it represents its initialization
>>> onlineapp.d(19):        opAssign methods are not used for 
>>> initialization, but for subsequent assignments
>>
>> Hm.. yeah, this seems not right. The compiler should just go ahead and 
>> initialize it if you try to call any methods on it (including 
>> opAssign) before initialization.
> 
> I think the struct should be initialised full stop. I mean whether a 
> member is initialised before the constructor is run shouldn't be 
> dependent on what you do in the constructor. I mean you declare a 
> struct, whether local or as part of an aggregate, it should be default 
> initialised. Its a simple orthogonal rule.

I didn't say it right - I mean that if you call a method on a struct, it 
should be treated as "initialized". It already initializes all the 
memory anyway.

> If it's to do with being able to modify immutable members in the 
> constructor that should be a separate rule. Either "You can modify 
> immutable members in a constructor", or "you can construct immutable 
> members in a constructor, but only once and it must be the first action 
> on the member"

It has to do with this:

struct S
{
    this(int) { writeln("ctor"); }
    void opAssign(int) { writeln("assignment"); }
}

S s = 5; // ctor
s = 5; // assignment

It is treating the first assignment of a member in a struct ctor as the 
initializer for the member. But if you have no ctor that matches, I see 
no reason why it shouldn't treat this as initializing (via default 
init), AND THEN calling opAssign on that.

It also makes NO sense to treat any usage of the struct after calling a 
member function on it as initializing. That seems to me a bug in the 
compiler implementation. That first function could have done anything to 
the struct.

> If there's a question of wasted effort initialising a member twice, the 
> compiler should be able to elide the default initialiser, at least in 
> simple cases the mechanism is already there.
> 
> They should be separate orthogonal rules.

The default initializer is happening anyway -- the opAssign or 
constructor is expecting it.

-Steve


More information about the Digitalmars-d mailing list