digitalmars.D.learn - Construct immutable member in derived class
- Timoses (21/24) Apr 04 2018 Example:
- Simen =?UTF-8?B?S2rDpnLDpXM=?= (24/49) Apr 04 2018 Because by the time B's constructor is called, A might already
- Timoses (28/52) Apr 04 2018 What about:
- Alex (7/12) Apr 04 2018 Here is something:
- Timoses (8/14) Apr 04 2018 "[...] the construction of the base class can be independent from
- Alex (25/32) Apr 05 2018 My reason is a semantic one, so it's rather how I'm explaining
- Jonathan M Davis (28/62) Apr 05 2018 The reality of the matter is that a member variable is a member of the c...
- Alex (5/28) Apr 05 2018 Yeah... little bit of mixing things up in my head, maybe... Did
- Jonathan M Davis (9/33) Apr 04 2018 That code doesn't compile - at least not with dmd master. It gives these...
- Timoses (7/43) Apr 04 2018 I know, should have mentioned it. The question is why, however?
- Jonathan M Davis (10/27) Apr 04 2018 Because doing that basically makes it impossible to guarantee that the t...
- Timoses (4/15) Apr 05 2018 Ah, makes sense. I was looking for a somewhat technical answer.
Example: ``` class A { immutable int i; this(){} } class B : A { this() { this.i = 3; } } void main() { auto b = new B; } ``` throws:Error: constructor `onlineapp.A.this` missing initializer for immutable field i Error: cannot modify immutable expression this.iWhy can't I initialize the immutable member in the derived class?
Apr 04 2018
On Wednesday, 4 April 2018 at 10:11:37 UTC, Timoses wrote:Example: ``` class A { immutable int i; this(){} } class B : A { this() { this.i = 3; } } void main() { auto b = new B; } ``` throws:Because by the time B's constructor is called, A might already have initialized it, and rely on it never changing. The solution is to add a constructor overload to A, and call that from B: class A { immutable int i; protected this(int i) { this.i = i; } } class B : A { this() { super(3); } } unittest { auto b = new B; } -- SimenError: constructor `onlineapp.A.this` missing initializer for immutable field i Error: cannot modify immutable expression this.iWhy can't I initialize the immutable member in the derived class?
Apr 04 2018
On Wednesday, 4 April 2018 at 10:41:52 UTC, Simen Kjærås wrote:Because by the time B's constructor is called, A might already have initialized it, and rely on it never changing.What about: ``` class A { immutable int i; this(){} } class B : A { this() { this.i = 3; super(); // <- specifically calling // super constructor afterwards } } void main() { auto b = new B; } ``` Same resultThe solution is to add a constructor overload to A, and call that from B: class A { immutable int i; protected this(int i) { this.i = i; } } class B : A { this() { super(3); } } unittest { auto b = new B; } -- SimenThis becomes a bit hideous, unfortunately, when there are many initializations involved. Found this, but it doesn't mention anything about derived classes.. https://dlang.org/spec/class.html#field-init
Apr 04 2018
On Wednesday, 4 April 2018 at 16:05:52 UTC, Timoses wrote:This becomes a bit hideous, unfortunately, when there are many initializations involved. Found this, but it doesn't mention anything about derived classes.. https://dlang.org/spec/class.html#field-initHere is something: https://dlang.org/spec/class.html#constructors By the rules 7 and 8 it is suggested, what Simen already said, the construction of the base class can be independent from the derived one. And as such, the immutability has to handled in the constructor, next to the variable...
Apr 04 2018
On Wednesday, 4 April 2018 at 16:16:24 UTC, Alex wrote:Here is something: https://dlang.org/spec/class.html#constructors By the rules 7 and 8 it is suggested, what Simen already said, the construction of the base class can be independent from the derived one. And as such, the immutability has to handled in the constructor, next to the variable..."[...] the construction of the base class can be independent from the derived one." Hm, the points 7 and 8 don't clearly state what you wrote. But it somehow does make sense.. Still I wonder why that is so. Let's say you have an abstract class with immutable members. Why shouldn't derived class constructors be allowed to initialize these immutable members?
Apr 04 2018
On Wednesday, 4 April 2018 at 21:49:08 UTC, Timoses wrote:"[...] the construction of the base class can be independent from the derived one." Hm, the points 7 and 8 don't clearly state what you wrote.Yes :)But it somehow does make sense.. Still I wonder why that is so. Let's say you have an abstract class with immutable members. Why shouldn't derived class constructors be allowed to initialize these immutable members?My reason is a semantic one, so it's rather how I'm explaining this to me, then a formal one. Let's assume, we abstract away a member from different derived classes to an abstract class, which cannot be handled by this abstract class. Ok, this can happen, so it would be ok, if the base class does not handle the var. But then, we add a qualifier. How can this be? As the abstract class cannot handle the abstraction, it also can not add any qualifiers. As the qualifier is there, then, the base class at least has knowledge about the immutability. And due this fact, its own constructor has to handle this variable in some way. However, this a minor problem, isn't it? If you argue, that you can also abstract the immutability qualifier, then, I would say, that a derived class always has a better knowledge how to handle its members, and therefore how to call the base class constructor, as it knows which class it is derived from. So, for short: Either: the immutability belongs to the base class and therefore it has to manage the var Or: it doesn't and the derived classes have the knowledge how to serve their base class.
Apr 05 2018
On Thursday, April 05, 2018 13:36:07 Alex via Digitalmars-d-learn wrote:On Wednesday, 4 April 2018 at 21:49:08 UTC, Timoses wrote:The reality of the matter is that a member variable is a member of the class that it's in and _must_ be handled by that class. If it's not directly initialized in its declaration or initialized in that class' constructor, then it gets a default value. Derived classes have _zero_ control over that. They can mutate a public or protected mutable member of a base class, but that member variable still has to be initialized by the base class, not the derived class. And you can't abstract whether a member variable is marked with immutable or not. That's part of the variable. Declaring an immutable instance of an object would then treat the member variable in immutable for that instance, so it's possible to have an immutable member variable when the member variable is not itself marked with immutable, but class inheritance has nothing to do with controlling which type qualifiers were used on the member variable of a base class. Derived classes override member functions. They don't override member variables or anything about them. They override the behavior of the base class, not the structure. For them to do otherwise would become quite problematic if you ever use a derived class through a base class reference. They can add onto the structure of a base class, but the derived class must be usuable via a base class reference, and trying to do something like have the derived class alter the qualifiers on base class member variable simply would not work with that. That sort of thing could only ever work if the base class were just a way to add functionality to a derived class rather than having anything to do with references, and that's simply not how classes work in D. If that's the sort of thing that you want, it would make more sense to add the functionality via composition rather than inheritance. - Jonathan M Davis"[...] the construction of the base class can be independent from the derived one." Hm, the points 7 and 8 don't clearly state what you wrote.Yes :)But it somehow does make sense.. Still I wonder why that is so. Let's say you have an abstract class with immutable members. Why shouldn't derived class constructors be allowed to initialize these immutable members?My reason is a semantic one, so it's rather how I'm explaining this to me, then a formal one. Let's assume, we abstract away a member from different derived classes to an abstract class, which cannot be handled by this abstract class. Ok, this can happen, so it would be ok, if the base class does not handle the var. But then, we add a qualifier. How can this be? As the abstract class cannot handle the abstraction, it also can not add any qualifiers. As the qualifier is there, then, the base class at least has knowledge about the immutability. And due this fact, its own constructor has to handle this variable in some way. However, this a minor problem, isn't it? If you argue, that you can also abstract the immutability qualifier, then, I would say, that a derived class always has a better knowledge how to handle its members, and therefore how to call the base class constructor, as it knows which class it is derived from. So, for short: Either: the immutability belongs to the base class and therefore it has to manage the var Or: it doesn't and the derived classes have the knowledge how to serve their base class.
Apr 05 2018
On Thursday, 5 April 2018 at 19:31:39 UTC, Jonathan M Davis wrote:And you can't abstract whether a member variable is marked with immutable or not. That's part of the variable. Declaring an immutable instance of an object would then treat the member variable in immutable for that instance, so it's possible to have an immutable member variable when the member variable is not itself marked with immutable, but class inheritance has nothing to do with controlling which type qualifiers were used on the member variable of a base class. Derived classes override member functions. They don't override member variables or anything about them. They override the behavior of the base class, not the structure.That beats my argumentation. Fully agree with that.For them to do otherwise would become quite problematic if you ever use a derived class through a base class reference. They can add onto the structure of a base class, but the derived class must be usuable via a base class reference, and trying to do something like have the derived class alter the qualifiers on base class member variable simply would not work with that. That sort of thing could only ever work if the base class were just a way to add functionality to a derived class rather than having anything to do with references, and that's simply not how classes work in D. If that's the sort of thing that you want, it would make more sense to add the functionality via composition rather than inheritance.Yeah... little bit of mixing things up in my head, maybe... Did exactly this stuff during the last couple of months. Thanks a lot!
Apr 05 2018
On Wednesday, April 04, 2018 16:05:52 Timoses via Digitalmars-d-learn wrote:On Wednesday, 4 April 2018 at 10:41:52 UTC, Simen Kjærås wrote:That code doesn't compile - at least not with dmd master. It gives these two errors: q.d(5): Error: constructor `q.A.this` missing initializer for immutable field i q.d(12): Error: cannot modify immutable expression this.i So, it's an error that the base class doesn't initialize the immutable member, and it's an error for the derived class to try to assign to it. - Jonathan M DavisBecause by the time B's constructor is called, A might already have initialized it, and rely on it never changing.What about: ``` class A { immutable int i; this(){} } class B : A { this() { this.i = 3; super(); // <- specifically calling // super constructor afterwards } } void main() { auto b = new B; } ```
Apr 04 2018
On Wednesday, 4 April 2018 at 18:11:12 UTC, Jonathan M Davis wrote:On Wednesday, April 04, 2018 16:05:52 Timoses viaI know, should have mentioned it. The question is why, however? A rule like the above would force all derived classes to initialize the immutable variable from the base class (if they were allowed to). Why aren't they?``` class A { immutable int i; this(){} } class B : A { this() { this.i = 3; super(); // <- specifically calling // super constructor afterwards } } void main() { auto b = new B; } ```That code doesn't compile - at least not with dmd master. It gives these two errors: q.d(5): Error: constructor `q.A.this` missing initializer for immutable field i q.d(12): Error: cannot modify immutable expression this.i So, it's an error that the base class doesn't initialize the immutable member, and it's an error for the derived class to try to assign to it. - Jonathan M Davis
Apr 04 2018
On Wednesday, April 04, 2018 21:46:13 Timoses via Digitalmars-d-learn wrote:On Wednesday, 4 April 2018 at 18:11:12 UTC, Jonathan M DavisBecause doing that basically makes it impossible to guarantee that the type system isn't violated. Once an immutable variable has been initialized, its value must _never_ change. It must be initalized exactly once, and the compiler doesn't necessarily have any clue what the base class constructors did or didn't do. There's no guarantee that it even has access to the function bodies for the base class when compiling the derived class. So, there is no way for it to safely put off the initialization of any base class members for the derived class to do. - Jonathan M DavisThat code doesn't compile - at least not with dmd master. It gives these two errors: q.d(5): Error: constructor `q.A.this` missing initializer for immutable field i q.d(12): Error: cannot modify immutable expression this.i So, it's an error that the base class doesn't initialize the immutable member, and it's an error for the derived class to try to assign to it.I know, should have mentioned it. The question is why, however? A rule like the above would force all derived classes to initialize the immutable variable from the base class (if they were allowed to). Why aren't they?
Apr 04 2018
On Wednesday, 4 April 2018 at 22:47:07 UTC, Jonathan M Davis wrote:Because doing that basically makes it impossible to guarantee that the type system isn't violated. Once an immutable variable has been initialized, its value must _never_ change. It must be initalized exactly once, and the compiler doesn't necessarily have any clue what the base class constructors did or didn't do. There's no guarantee that it even has access to the function bodies for the base class when compiling the derived class. So, there is no way for it to safely put off the initialization of any base class members for the derived class to do. - Jonathan M DavisAh, makes sense. I was looking for a somewhat technical answer. Thanks for that : ).
Apr 05 2018