digitalmars.D - Is this really intended??
- claptrap (41/41) Oct 10 2020 struct Foo
- Paul Backus (18/28) Oct 10 2020 The first assignment to a member inside a constructor is
- Adam D. Ruppe (6/9) Oct 10 2020 This isn't what's weird here though, the bizarre thing is it lets
- Steven Schveighoffer (12/67) Oct 11 2020 Hm.. yeah, this seems not right. The compiler should just go ahead and
- claptrap (17/48) Oct 11 2020 I think the struct should be initialised full stop. I mean
- Paul Backus (18/24) Oct 11 2020 This is how the language already works, at least according to the
- Steven Schveighoffer (23/72) Oct 11 2020 I didn't say it right - I mean that if you call a method on a struct, it...
- claptrap (16/29) Oct 13 2020 I didn't realise the default initialiser and constructor were
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 With *2 commented out it compiles with no errors With *1 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 Arn't structs supposed to be default initialised? But in a constructor a struct member is not? If you write to a field in a struct member suddenly it is considered initialised? And yet it's OK to call a method on the struct that is not initialised, but if you do it's still uninitialised? Why should foo.i = 0; foo.reset(); Result in the compiler changing whether it's OK to call opAssign? That's some weird ****.
Oct 10 2020
On Sunday, 11 October 2020 at 00:16:53 UTC, claptrap wrote:Arn't structs supposed to be default initialised? But in a constructor a struct member is not? If you write to a field in a struct member suddenly it is considered initialised? And yet it's OK to call a method on the struct that is not initialised, but if you do it's still uninitialised? Why should foo.i = 0; foo.reset(); Result in the compiler changing whether it's OK to call opAssign?The first assignment to a member inside a constructor is considered initialization so that you can use constructors to initialize immutable members: struct Example { immutable int i; this(int i) { this.i = i; // ok, initialization this.i = 42; // error, assignment to immutable variable } } One consequence of this is that the first assignment does not call opAssign, since opAssign isn't used for initialization. I agree that this is kind of a hack. A more principled way to handle this would be to introduce a separate syntax for initialization, like `let this.i = i` or `this.i := i`.
Oct 10 2020
On Sunday, 11 October 2020 at 00:34:57 UTC, Paul Backus wrote:The first assignment to a member inside a constructor is considered initialization so that you can use constructors to initialize immutable members:This isn't what's weird here though, the bizarre thing is it lets you call the method on the "uninitialized" member, then proceed to initialize it afterward. The rest of it is justified, but that particular aspect is bizarre and I can't justify that...
Oct 10 2020
On Sunday, 11 October 2020 at 00:39:54 UTC, Adam D. Ruppe wrote:On Sunday, 11 October 2020 at 00:34:57 UTC, Paul Backus wrote:I though structs were default initialised? I mean I remember reading here that one of the design axioms of structs is that that have a simple bitblit for initialisation? Is that not done for members if their enclosing aggregate has a constructor? If you have... struct Foo { int i; } struct Bar { Foo foo; this() {} } Is foo not initialised before entry to Bars constructor? It cant be after, so it must be before, or is it not called at all if foo is explicitly initialised in Foo.this?The first assignment to a member inside a constructor is considered initialization so that you can use constructors to initialize immutable members:This isn't what's weird here though, the bizarre thing is it lets you call the method on the "uninitialized" member, then proceed to initialize it afterward. The rest of it is justified, but that particular aspect is bizarre and I can't justify that...
Oct 11 2020
On Sunday, 11 October 2020 at 09:55:31 UTC, claptrap wrote:if foo is explicitly initialised in Foo.this?I mean "Bar.this"
Oct 11 2020
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 assignmentsHm.. 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. note that if you define a constructor for Foo that takes an int, it would work (and use that when you assigned it to 42). But it shouldn't need this, IMO. What's really bizarre is if you comment *1 out, it still complains. If you called reset on it, is it not already initialized???!With *2 commented out it compiles with no errors With *1 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 Arn't structs supposed to be default initialised? But in a constructor a struct member is not? If you write to a field in a struct member suddenly it is considered initialised? And yet it's OK to call a method on the struct that is not initialised, but if you do it's still uninitialised? Why should foo.i = 0; foo.reset(); Result in the compiler changing whether it's OK to call opAssign? That's some weird ****.This makes no sense. I think this is worth a bug report. The compiler should be a bit smarter (dumber?) on flow checking here. -Steve
Oct 11 2020
On Sunday, 11 October 2020 at 18:57:55 UTC, Steven Schveighoffer wrote:On 10/10/20 8:16 PM, claptrap wrote: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. 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" 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.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 assignmentsHm.. 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.
Oct 11 2020
On Sunday, 11 October 2020 at 21:50:28 UTC, claptrap wrote: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.This is how the language already works, at least according to the spec: When an instance of a struct is created, the following steps happen: 1. The raw data is statically initialized using the values provided in the struct definition. This operation is equivalent to doing a memory copy of a static version of the object onto the newly allocated one. 2. If there is a constructor defined for the struct, the constructor matching the argument list is called. 3. If struct invariant checking is turned on, the struct invariant is called at the end of the constructor. Source: https://dlang.org/spec/struct.html#struct-instantiation
Oct 11 2020
On 10/11/20 5:50 PM, claptrap wrote:On Sunday, 11 October 2020 at 18:57:55 UTC, Steven Schveighoffer wrote: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.On 10/10/20 8:16 PM, claptrap wrote: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.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 assignmentsHm.. 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.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
Oct 11 2020
On Sunday, 11 October 2020 at 22:11:48 UTC, Steven Schveighoffer wrote:On 10/11/20 5:50 PM, claptrap wrote:I didn't realise the default initialiser and constructor were separate required events. I thought default initialisation was enough, the constructors is there if you want something more than the default init. I guess that the error message isn't very clear either since it talks about initialisation when really it's construction that is needed. I mean if the language is going to differentiate between initialisation and construction, the error message should be clear which one is missing. In fact if the struct has no constructors it can only be default initialised anyway, so it's seems pointless for the compiler to require a constructor to be called when it's essentially a NOP. I mean if the struct has no constructor, then it should be considered fully constructed after the default init.On Sunday, 11 October 2020 at 18:57:55 UTC, Steven Schveighoffer wrote:The default initializer is happening anyway -- the opAssign or constructor is expecting it.On 10/10/20 8:16 PM, claptrap wrote: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.
Oct 13 2020