Jump to page: 1 2
Thread overview
Construct immutable member in derived class
Apr 04, 2018
Timoses
Apr 04, 2018
Simen Kjærås
Apr 04, 2018
Timoses
Apr 04, 2018
Alex
Apr 04, 2018
Timoses
Apr 05, 2018
Alex
Apr 05, 2018
Jonathan M Davis
Apr 05, 2018
Alex
Apr 04, 2018
Jonathan M Davis
Apr 04, 2018
Timoses
Apr 04, 2018
Jonathan M Davis
Apr 05, 2018
Timoses
April 04, 2018
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.i

Why can't I initialize the immutable member in the derived class?
April 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:
>> Error: constructor `onlineapp.A.this` missing initializer for immutable field i
>> Error: cannot modify immutable expression this.i
>
> Why can't I initialize the immutable member in the derived class?

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;
}

--
  Simen
April 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 result

> 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;
> }
>
> --
>   Simen

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-init
April 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-init

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...
April 04, 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:
> > 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;
> }
> ```

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


April 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 via
>>
>> ```
>> 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

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?
April 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?
April 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 Davis
> > 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.
>
> 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?

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 Davis

April 05, 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.
April 05, 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 Davis

Ah, makes sense. I was looking for a somewhat technical answer. Thanks for that : ).
« First   ‹ Prev
1 2