www.digitalmars.com         C & C++   DMDScript  

digitalmars.dip.ideas - Struct inheritance

reply Richard (Rikki) Andrew Cattermole <richard cattermole.co.nz> writes:
As an idea this has come up in Razvan's DConf 2024 talk.

1. Support inheritance on struct, for other structs.

```d
struct Parent {
     ...
}

struct Child : Parent {
     ...
}
```

2. ``opDispatch`` function, may work in place of ``alias this`` 
when no parent exists.

```d
struct Parent {
     T thing;
     ref T opDispatch(string:"")() {
         return this.thing;
     }
}

struct Child : Parent {
}

Child child;
T got = child;
```
Sep 19
next sibling parent reply Nick Treleaven <nick geany.org> writes:
On Thursday, 19 September 2024 at 15:56:06 UTC, Richard (Rikki) 
Andrew Cattermole wrote:
 As an idea this has come up in Razvan's DConf 2024 talk.

 1. Support inheritance on struct, for other structs.

 ```d
 struct Parent {
     ...
 }

 struct Child : Parent {
     ...
 }
 ```
In the talk, Walter mentioned doing that instead of having `alias this`. That would be much less powerful. `alias this` allows hooking conversion to the target type. With `alias this = func; T func();`, you can create the T instance at runtime. It doesn't even have to be the same instance each time. Also T doesn't have to be a struct.
 2. ``opDispatch`` function, may work in place of ``alias this`` 
 when no parent exists.

 ```d
 struct Parent {
     T thing;
     ref T opDispatch(string:"")() {
         return this.thing;
     }
 }

 struct Child : Parent {
 }

 Child child;
 T got = child;
 ```
This seems like `alias this` in disguise.
Sep 19
parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 20/09/2024 6:57 AM, Nick Treleaven wrote:
 This seems like |alias this| in disguise.
The problem with alias this, is it is not defined as the fallback when nothing else in the hierarchy matches. Here it is better defined, opDispatch should only be chosen after exhausting the hierarchy, both in classes and structs. Eliminating the issues with alias this from the design. We can further restrict it, to only support the parent most type in the hierarchy or only one in the hierarchy. In effect it allows adding a new parent to the top of the hierarchy.
Sep 19
next sibling parent "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 20/09/2024 7:04 AM, Richard (Rikki) Andrew Cattermole wrote:
 On 20/09/2024 6:57 AM, Nick Treleaven wrote:
 This seems like |alias this| in disguise.
The problem with alias this, is it is not defined as the fallback when nothing else in the hierarchy matches. Here it is better defined, opDispatch should only be chosen after exhausting the hierarchy, both in classes and structs. Eliminating the issues with alias this from the design. We can further restrict it, to only support the parent most type in the hierarchy or only one in the hierarchy. In effect it allows adding a new parent to the top of the hierarchy.
I should mention that this aspect of the proposal while it add new semantics, doesn't have anything special related to the rules of acceptability of opDispatch itself. We'll need to define how opDispatch works in the hierarchy. Otherwise we'll have come right back to the same set of issues as alias this has.
Sep 19
prev sibling parent reply Nick Treleaven <nick geany.org> writes:
On Thursday, 19 September 2024 at 19:04:40 UTC, Richard (Rikki) 
Andrew Cattermole wrote:
 On 20/09/2024 6:57 AM, Nick Treleaven wrote:
 This seems like |alias this| in disguise.
The problem with alias this, is it is not defined as the fallback when nothing else in the hierarchy matches. Here it is better defined, opDispatch should only be chosen after exhausting the hierarchy, both in classes and structs.
I don't see why you want to overload opDispatch to do subtyping. It doesn't seem related to existing opDispatch.
 Eliminating the issues with alias this from the design.

 We can further restrict it, to only support the parent most 
 type in the hierarchy or only one in the hierarchy. In effect 
 it allows adding a new parent to the top of the hierarchy.
I don't think we need to restrict its capabilities, we just need another syntax for it so we can fix the semantics. If anything I'd like to increase its capabilities. It could be defined as a template method and instantiated with the type of the expected result, and the constraint determines whether the conversion is enabled for that type. In effect, allowing multiple `alias this` with the semantics defined by the aggregate author.
Sep 20
next sibling parent "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 21/09/2024 3:23 AM, Nick Treleaven wrote:
     Eliminating the issues with alias this from the design.
 
     We can further restrict it, to only support the parent most type in
     the hierarchy or only one in the hierarchy. In effect it allows
     adding a new parent to the top of the hierarchy.
 
 I don't think we need to restrict its capabilities, we just need another 
 syntax for it so we can fix the semantics. If anything I'd like to 
 increase its capabilities. It could be defined as a template method and 
 instantiated with the type of the expected result, and the constraint 
 determines whether the conversion is enabled for that type. In effect, 
 allowing multiple |alias this| with the semantics defined by the 
 aggregate author.
Ok so basically implicit conversions with optional target type. As long as it is defined as being last resort after looking up through the hierarchy, then that aspect I'm ok with. Child most definition only. You'll need to convince Walter wrt. argument to parameter matching, and he has some strong feelings on this. But as far as the syntax changes are concerned for no target type, I'm ok with that being swapped to, it'll give it somewhere to expand to in the future.
Sep 20
prev sibling parent user1234 <user1234 12.de> writes:
On Friday, 20 September 2024 at 15:23:25 UTC, Nick Treleaven 
wrote:
 On Thursday, 19 September 2024 at 19:04:40 UTC, Richard (Rikki) 
 Andrew Cattermole wrote:
 On 20/09/2024 6:57 AM, Nick Treleaven wrote:
 This seems like |alias this| in disguise.
The problem with alias this, is it is not defined as the fallback when nothing else in the hierarchy matches. Here it is better defined, opDispatch should only be chosen after exhausting the hierarchy, both in classes and structs.
I don't see why you want to overload opDispatch to do subtyping. It doesn't seem related to existing opDispatch.
 Eliminating the issues with alias this from the design.

 We can further restrict it, to only support the parent most 
 type in the hierarchy or only one in the hierarchy. In effect 
 it allows adding a new parent to the top of the hierarchy.
I don't think we need to restrict its capabilities, we just need another syntax for it so we can fix the semantics. If anything I'd like to increase its capabilities. It could be defined as a template method and instantiated with the type of the expected result, and the constraint determines whether the conversion is enabled for that type. [...]
It's basically the same as `opCast` but called without `cast`. A long time ago this was discussed, (we called that opImpcConvRight). That thing would work but to fix `alias this` problems then the users need to overload much more operators, and that becomes unatural to use, i.e vs `alias this` which works more naturally. Fact is there are plenty of situation where implicit convs are not tried but you want that new op to be tried. Basically that's the exact same situations where currently the compiler has to try if `alias this` is possible.
Sep 20
prev sibling next sibling parent Paul Backus <snarwin gmail.com> writes:
On Thursday, 19 September 2024 at 15:56:06 UTC, Richard (Rikki) 
Andrew Cattermole wrote:
 As an idea this has come up in Razvan's DConf 2024 talk.
Last time this came up on the forums, I did a quick search through Phobos to see how many uses of `alias this` forwarded to a member variable (and could be replaced by struct inheritance) and how many forwarded to a function. My hypothesis before actually checking was that `alias this` to a member variable would be significantly more common than `alias this` to a function. But in reality, they turned out to be equally common. Original post: https://forum.dlang.org/post/nbysytbybvqwgxvdexym forum.dlang.org
Sep 19
prev sibling next sibling parent reply IchorDev <zxinsworld gmail.com> writes:
On Thursday, 19 September 2024 at 15:56:06 UTC, Richard (Rikki) 
Andrew Cattermole wrote:
 As an idea this has come up in Razvan's DConf 2024 talk.

 1. Support inheritance on struct, for other structs.
 2. ``opDispatch`` function, may work in place of ``alias this`` 
 when no parent exists.
What about interfaces?
Sep 20
parent "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 20/09/2024 10:14 PM, IchorDev wrote:
 On Thursday, 19 September 2024 at 15:56:06 UTC, Richard (Rikki) Andrew 
 Cattermole wrote:
 As an idea this has come up in Razvan's DConf 2024 talk.

 1. Support inheritance on struct, for other structs.
 2. ``opDispatch`` function, may work in place of ``alias this`` when 
 no parent exists.
What about interfaces?
While I do want signatures which would fill this void, the purpose of this is to get rid of alias this which has some problematic behaviors in symbol lookup.
Sep 20
prev sibling next sibling parent reply Ogion <ogion.art gmail.com> writes:
On Thursday, 19 September 2024 at 15:56:06 UTC, Richard (Rikki) 
Andrew Cattermole wrote:
Would be nice to have proper struct inheritance but there are a lot of things we have to consider. What about slicing? ```D struct A { int x; } struct B : A { int y; this(int x, int y) { super(x); this.y = y; } } void main() { B b1 = B(1, 2), b2 = B(3, 4); A* p = &b2; *p = b1; writeln(b2); // B(1, 4) } ``` If we want something better than `alias this`, we have to prohibit implicit partial assignment via pointer/reference. When it’s necessary, it would still be possible with `*p = cast(A)b1;`.
Sep 23
next sibling parent "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 24/09/2024 2:52 AM, Ogion wrote:
 On Thursday, 19 September 2024 at 15:56:06 UTC, Richard (Rikki) Andrew 
 Cattermole wrote:
Would be nice to have proper struct inheritance but there are a lot of things we have to consider. What about slicing? ```D struct A {     int x; } struct B : A {     int y;     this(int x, int y) {         super(x);         this.y = y;     } } void main() {     B b1 = B(1, 2), b2 = B(3, 4);     A* p = &b2;     *p = b1;     writeln(b2); // B(1, 4) } ``` If we want something better than `alias this`, we have to prohibit implicit partial assignment via pointer/reference. When it’s necessary, it would still be possible with `*p = cast(A)b1;`.
It is probably better to completely disable casting up the hierarchy in `` safe`` code. If you need that, use ``opCast``. It is not like with classes, where its guaranteed to have an allocation containing the entire thing, with a vtable. Only concern is when you've got a pointer to a struct, and you cast up. ``opCast!(A*)`` support is likely what we want I think. I'm not sure how we'd do that one. Maybe an attribute?
Sep 23
prev sibling parent Brad Roberts <braddr puremagic.com> writes:
On 9/23/2024 7:52 AM, Ogion via dip.ideas wrote:
 On Thursday, 19 September 2024 at 15:56:06 UTC, Richard (Rikki) Andrew 
 Cattermole wrote:
Would be nice to have proper struct inheritance but there are a lot of things we have to consider.
Careful with the term 'proper'. It doesn't add clarity. It does implicitly divide everything else into some vague other category of improper, but without actually helping describe any actual particulars.
Sep 23
prev sibling next sibling parent reply Derek Fawcus <dfawcus+dlang employees.org> writes:
On Thursday, 19 September 2024 at 15:56:06 UTC, Richard (Rikki) 
Andrew Cattermole wrote:
 As an idea this has come up in Razvan's DConf 2024 talk.

 1. Support inheritance on struct, for other structs.

 ```d
 struct Parent {
     ...
 }

 struct Child : Parent {
     ...
 }
 ```

 2. ``opDispatch`` function, may work in place of ``alias this`` 
 when no parent exists.

 ```d
 struct Parent {
     T thing;
     ref T opDispatch(string:"")() {
         return this.thing;
     }
 }

 struct Child : Parent {
 }

 Child child;
 T got = child;
 ```
As I recall, the main purpose of 'alias this' is to offer implicit conversion of types. There is also the ability to have a member function called (property-like?), which seems like a somewhat different purpose. When I first saw this inheritance suggestion mentioned (possibly in a recording of one of the DConf sessions), it struck me that something like the 'struct embedding' together with its implicit conversion for member functions on the embedded type may provide a similar mechanism. This is something which is offered by Go/Limbo/Alef/Ken-C, the latter being used as the Plan 9 C compiler. As I recall in the latter it was used for something like: ```C struct Lock { ... }; bool lockit(struct Lock *); struct Foo { ... Lock; ... }; void something(/* ... */) { struct Foo *foo = something_returning_Foo(/* ... */); if (!lockit(foo) { /* some error handling */ } ... } ``` Where the use of lockit() above is then called with '&foo->Lock' as an implicit conversion. Personally, I'd rather have a struct like (POD) thing, even with member functions, which does not allow for the possibility of classful behaviour. If classful behaviour is desired, then somehow adjust classes so that they can be easily used as non-reference types.
Dec 03
next sibling parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 04/12/2024 8:15 AM, Derek Fawcus wrote:
 As I recall, the main purpose of 'alias this' is to offer implicit 
 conversion of types.  There is also the ability to have a member 
 function called (property-like?), which seems like a somewhat different 
 purpose.
It is two functionalities yes. Which is why I've included both the inheritance as well as the reparenting behavior. Otherwise it isn't a complete replacement.
 When I first saw this inheritance suggestion mentioned (possibly in a 
 recording of one of the DConf sessions), it struck me that something 
 like the 'struct embedding' together with its implicit conversion for 
 member functions on the embedded type may provide a similar mechanism.
 
 This is something which is offered by Go/Limbo/Alef/Ken-C, the latter 
 being used as the Plan 9 C compiler.
 
 As I recall in the latter it was used for something like:
 
 ```C
 struct Lock {
    ...
 };
 
 bool lockit(struct Lock *);
 
 struct Foo {
     ...
     Lock;
     ...
 };
 
 void something(/* ... */)
 {
      struct Foo *foo = something_returning_Foo(/* ... */);
 
      if (!lockit(foo) {
          /* some error handling */
      }
 
      ...
 }
 ```
 
 Where the use of lockit() above is then called with '&foo->Lock' as an 
 implicit conversion.
As a syntax that would imply multiple of these are possible. Classes in D do not support multiple parent classes, so I don't think adding it for structs is appropriate. If you don't need multiple parents, then the existing syntax works fine. ```d struct Parent { } struct Foo : Parent { } ```
 Personally, I'd rather have a struct like (POD) thing, even with member 
 functions, which does not allow for the possibility of classful 
 behaviour.  If classful behaviour is desired, then somehow adjust 
 classes so that they can be easily used as non-reference types.
The class behavior that I do not want here is vtables and casting. Both of these have very good reasons why they would not be appropriate. So there would be differences between them with good reasons why you would want classes over structs still.
Dec 03
parent reply Derek Fawcus <dfawcus+dlang employees.org> writes:
On Tuesday, 3 December 2024 at 19:25:08 UTC, Richard (Rikki) 
Andrew Cattermole wrote:
 On 04/12/2024 8:15 AM, Derek Fawcus wrote:
 As I recall, the main purpose of 'alias this' is to offer 
 implicit conversion of types.  There is also the ability to 
 have a member function called (property-like?), which seems 
 like a somewhat different purpose.
It is two functionalities yes. Which is why I've included both the inheritance as well as the reparenting behavior. Otherwise it isn't a complete replacement.
 As a syntax that would imply multiple of these are possible.
Yes, but it is literally equivalent to explicitly embedded one struct in another, which is already possible. So one could have: ```C struct Foo; struct Bar; struct Wrapper { ... Foo; Bar; ... }; ``` Which is just sugar for this: ```C struct Wrapper { ... struct Foo Foo; struct Bar Bar; ... }; ``` It is just that having the embedded form allows the implicit conversion to happen, as it is a simple unambiguous sugar for accessing the appropriate member.
 Classes in D do not support multiple parent classes, so I don't 
 think adding it for structs is appropriate.
Except D also already allows the explicit form above, but not the sugar for the field reference. This is not inheritance, so there are no issues with embedding multiple structs, no diamond pattern issues, etc. (I believe the Go spec explains all of this.) What this gives is the implicit field conversion which 'alias this' seems to offer some form of, but in a different syntactical form, and allowing multiple such conversions. However it probably won't cover all implicit conversion uses, e.g. 'alias this' to an 'int' member, then assigning the struct to an int var. The scheme I'm suggesting only really covers calling functions with argument conversion.
 If you don't need multiple parents, then the existing syntax 
 works fine.

 ```d
 struct Parent {
 }

 struct Foo : Parent {
 }
 ```
Would your proposal allow: ```d struct Grandad { } struct Dad : Grandad { } struct Child : Dad { } ``` (I'm not sure if the scheme I mention does, I'd have to reread the specs; but I believe it doesn't).
Dec 03
parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 04/12/2024 9:19 AM, Derek Fawcus wrote:
 On Tuesday, 3 December 2024 at 19:25:08 UTC, Richard (Rikki) Andrew 
 Cattermole wrote:
 On 04/12/2024 8:15 AM, Derek Fawcus wrote:
 As I recall, the main purpose of 'alias this' is to offer implicit 
 conversion of types.  There is also the ability to have a member 
 function called (property-like?), which seems like a somewhat 
 different purpose.
It is two functionalities yes. Which is why I've included both the inheritance as well as the reparenting behavior. Otherwise it isn't a complete replacement.
 As a syntax that would imply multiple of these are possible.
Yes, but it is literally equivalent to explicitly embedded one struct in another, which is already possible.  So one could have: ```C struct Foo; struct Bar; struct Wrapper {     ...     Foo;     Bar;     ... }; ``` Which is just sugar for this: ```C struct Wrapper {     ...     struct Foo Foo;     struct Bar Bar;     ... }; ``` It is just that having the embedded form allows the implicit conversion to happen, as it is a simple unambiguous sugar for accessing the appropriate member.
I'm very wary of this, Walter is pretty against implicit conversions generally speaking. I'm still trying to get a confirmation about the member-of-operator out of Walter which I have implemented (missing like two features). Given that the utility of this is highly restricted to a subset of compositional needs, and the fact that it relies upon implicit conversions, I do not expect that this would be accepted. However, I am in no way arguing against composition, I agree that it is better than inheritance normally. What this would be replacing, is not where composition is most valuable for. Just in case you are interested, this is the function you would need to modify to implement the matching. https://github.com/dlang/dmd/blob/d8c0e79bfb9ddb0e50603ffafa4c3d5539934f48/compiler/src/dmd/typesem.d#L998
 Classes in D do not support multiple parent classes, so I don't think 
 adding it for structs is appropriate.
Except D also already allows the explicit form above, but not the sugar for the field reference.  This is not inheritance, so there are no issues with embedding multiple structs, no diamond pattern issues, etc. (I believe the Go spec explains all of this.)
I got all that. There is are issues from my perspective surrounding its compositional nature.
 What this gives is the implicit field conversion which 'alias this' 
 seems to offer some form of, but in a different syntactical form, and 
 allowing multiple such conversions.
 
 However it probably won't cover all implicit conversion uses, e.g. 
 'alias this' to an 'int' member, then assigning the struct to an int 
 var.  The scheme I'm suggesting only really covers calling functions 
 with argument conversion.
Right, its a tool for composition. Different set of problems.
 If you don't need multiple parents, then the existing syntax works fine.

 ```d
 struct Parent {
 }

 struct Foo : Parent {
 }
 ```
Would your proposal allow: ```d struct Grandad { } struct Dad : Grandad { } struct Child : Dad { } ``` (I'm not sure if the scheme I mention does, I'd have to reread the specs; but I believe it doesn't).
Yes.
Dec 03
parent reply Derek Fawcus <dfawcus+dlang employees.org> writes:
On Tuesday, 3 December 2024 at 20:45:32 UTC, Richard (Rikki) 
Andrew Cattermole wrote:

 Would your proposal allow:
 
 ```d
 struct Grandad {
 }
 
 struct Dad : Grandad {
 }
 
 struct Child : Dad {
 }
 ```
 
 (I'm not sure if the scheme I mention does, I'd have to reread 
 the specs; but I believe it doesn't).
Yes.
OK. I'd suggest that the member variable version of 'alias this' is also a form of embedding / composition. It allows one to control the exact in-memory layout of the struct so defined. Whereas AFAICT, the inheritance suggestion does not. Issues/Questions with inheritance suggestion: 1. What is the in memory layout? (Presumably the 'parent' elements simply appear first in memory). 2. Inability to control in memory layout. 3. What type is passed to a parent struct member function when called on the child. (Presumably it is the class behaviour of passing the child stuct, with 'isA' relations) (If not, then there are two different behaviours for inheritance - class vs struct) 4. What other parts of the class behaviour will apply? (i.e. will the class implicit mutex lock now be instantiated) (if not, then classes and structs using inheritance will have different threading behaviour)
Dec 03
parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 04/12/2024 10:37 AM, Derek Fawcus wrote:
 On Tuesday, 3 December 2024 at 20:45:32 UTC, Richard (Rikki) Andrew 
 Cattermole wrote:
 
 Would your proposal allow:

 ```d
 struct Grandad {
 }

 struct Dad : Grandad {
 }

 struct Child : Dad {
 }
 ```

 (I'm not sure if the scheme I mention does, I'd have to reread the 
 specs; but I believe it doesn't).
Yes.
OK. I'd suggest that the member variable version of 'alias this' is also a form of embedding / composition. It allows one to control the exact in-memory layout of the struct so defined. Whereas AFAICT, the inheritance suggestion does not. Issues/Questions with inheritance suggestion: 1. What is the in memory layout?    (Presumably the 'parent' elements simply appear first in memory).
Yes, that would be my thought.
 2. Inability to control in memory layout.
If you need the control between last field of parent, and first of child, I suspect that this isn't the language feature for you. But if we do need to solve it, we could solve it later on with an attribute. I don't think there is a better way to do it than an attribute, so this can be done later on should we need it, rather than arguing about it now.
 3. What type is passed to a parent struct member function when called on 
 the child.
     (Presumably it is the class behaviour of passing the child stuct, 
 with 'isA' relations)
     (If not, then there are two different behaviours for inheritance - 
 class vs struct)
A class will pass a this pointer typed as its class, not a child. ```d import std.stdio; void main() { Child child = new Child; child.method(); Parent parent = child; parent.method; } class Parent { void method() { writeln(typeof(this).stringof); } } class Child : Parent { override void method() { super.method(); writeln(typeof(this).stringof); } } ``` Will output: ``` Parent Child Parent Child ``` Struct inheritance would have the same output.
 4. What other parts of the class behaviour will apply?
     (i.e. will the class implicit mutex lock now be instantiated)
     (if not, then classes and structs using inheritance will have 
 different threading behaviour)
There is no vtable, no root type (Object class provides the mutex). Therefore unless its stated, no behavior from classes is coming across to structs. Note: classes do not lock the mutex automatically for you. You must specify the synchronized keyword to make it do it. Unless specified by the user, the temporal properties of each match. Existing structs will not change behavior.
Dec 03
parent reply Derek Fawcus <dfawcus+dlang employees.org> writes:
On Tuesday, 3 December 2024 at 23:18:12 UTC, Richard (Rikki) 
Andrew Cattermole wrote:

Sorry, I had Obj-C in mind when I wrote that, and my use of that 
was over 10 years ago; hence my confusion.

So what would your scheme do for the struct equivalent of this, 
assuming it is even compiles:

```d
import std.stdio;

void main() {
     Child child = new Child;
     child.methB();

     writeln();
     Parent parent = child;
     parent.methB;
}

class Parent {
     void methB() {
      	writeln("MethB(P) ", typeof(this).stringof);
	methC();
     }
     void methC() {
      	writeln("MethB(P) ", typeof(this).stringof);
     }
}

class Child : Parent {
     override void methC() {
      	writeln("MethC(C) ", typeof(this).stringof);
     }
}
```

Where the above give this output:

```
$ ldc2 -run class.d
MethB(P) Parent
MethC(C) Child

MethB(P) Parent
MethC(C) Child
```
Dec 04
parent reply Derek Fawcus <dfawcus+dlang employees.org> writes:
(That was a bit iffy, try this one instead)

On Wednesday, 4 December 2024 at 11:10:59 UTC, Derek Fawcus wrote:
 So what would your scheme do for the struct equivalent of this, 
 assuming it is even compiles:
```D import std.stdio; void main() { Parent parent = new Parent; parent.methB("Direct"); writeln(); Child child = new Child; child.methB("Inherit"); writeln(); parent = child; parent.methB("Assign"); } class Parent { void methB(string s) { writeln("MethB(P) ", s, " ", typeof(this).stringof); methC(s); } void methC(string s) { writeln("MethC(P) ", s, " ", typeof(this).stringof); } } class Child : Parent { override void methC(string s) { writeln("MethC(C) ", s, " ", typeof(this).stringof); } } ``` For which I get: ``` MethB(P) Direct Parent MethC(P) Direct Parent MethB(P) Inherit Parent MethC(C) Inherit Child MethB(P) Assign Parent MethC(C) Assign Child ```
Dec 04
parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 05/12/2024 12:38 AM, Derek Fawcus wrote:
 For which I get:
 
 ```
 MethB(P) Direct Parent
 MethC(P) Direct Parent
 
 MethB(P) Inherit Parent
Due to no vtables, you cannot override a parent method and have it see the override. MethC(C) Inherit Parent
 ```
The last example, assignment, this requires vtables and casting up. Which structs cannot do.
Dec 04
parent reply Derek Fawcus <dfawcus+dlang employees.org> writes:
On Wednesday, 4 December 2024 at 11:51:57 UTC, Richard (Rikki) 
Andrew Cattermole wrote:
 On 05/12/2024 12:38 AM, Derek Fawcus wrote:
 For which I get:
 
 ```
 MethB(P) Direct Parent
 MethC(P) Direct Parent
 
 MethB(P) Inherit Parent
Due to no vtables, you cannot override a parent method and have it see the override. MethC(C) Inherit Parent
 ```
The last example, assignment, this requires vtables and casting up. Which structs cannot do.
So are you saying all three would be like the 'Direct Parent' case? Presumably by making the Assign case cheat (manually forcibly casting a pointer of the child to a pointer of the parent), it would also yield the same result. i.e.: ``` MethB(P) Direct Parent MethC(P) Direct Parent MethB(P) Inherit Parent MethC(P) Inherit Parent MethB(P) Assign Parent MethC(P) Assign Parent ``` Or for the child method override, would you simply yield a compile failure - as it can never work, and has no backward compatibility issue?
Dec 04
parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 05/12/2024 1:03 AM, Derek Fawcus wrote:
 On Wednesday, 4 December 2024 at 11:51:57 UTC, Richard (Rikki) Andrew 
 Cattermole wrote:
 On 05/12/2024 12:38 AM, Derek Fawcus wrote:
 For which I get:

 ```
 MethB(P) Direct Parent
 MethC(P) Direct Parent

 MethB(P) Inherit Parent
Due to no vtables, you cannot override a parent method and have it see the override. MethC(C) Inherit Parent
 ```
The last example, assignment, this requires vtables and casting up. Which structs cannot do.
So are you saying all three would be like the 'Direct Parent' case? Presumably by making the Assign case cheat (manually forcibly casting a pointer of the child to a pointer of the parent), it would also yield the same result.
Casting a pointer to the parent, would be `` system``, so what it does is very much "good luck with that".
 i.e.:
 
 ```
 MethB(P) Direct Parent
 MethC(P) Direct Parent
 
 MethB(P) Inherit Parent
 MethC(P) Inherit Parent
 
 MethB(P) Assign Parent
 MethC(P) Assign Parent
 ```
 
 Or for the child method override, would you simply yield a compile 
 failure - as it can never work, and has no backward compatibility issue?
In a situation such as: ```d struct Parent { void method1() { method2(); } void method2() { } } struct Child : Parent { override void method2() { } } ``` My general view is that you have to be a little bit smart about it. There may be reasons you would want something like this, but there is also reasons it might not be desired. I want a way to reinterpret parent methods as if it was in the child if not overriden. At which point ``method1`` would see the child ``method2`` rather than the one in the parent.
Dec 04
parent reply Derek Fawcus <dfawcus+dlang employees.org> writes:
On Wednesday, 4 December 2024 at 12:43:49 UTC, Richard (Rikki) 
Andrew Cattermole wrote:
 Casting a pointer to the parent, would be `` system``, so what 
 it does is very much "good luck with that".
Which I guess is reasonable, or even have it as undefined behaviour.
 In a situation such as:

 ```d
 struct Parent {
 	void method1() {
 		method2();
 	}

 	void method2() {
 	}
 }

 struct Child : Parent {
 	override void method2() {
 	}
 }
 ```

 My general view is that you have to be a little bit smart about 
 it.

 There may be reasons you would want something like this, but 
 there is also reasons it might not be desired.
My thinking, and reason for asking, is that two different authors may be involved. One would not wish the fact that someone had Child inherit from Parent cause the behaviour of Parent to change, that way lies madness. Given these are structs, not classes; and the author of Parent would have no expectation of anything other than its own method being called.
 I want a way to reinterpret parent methods as if it was in the 
 child if not overriden. At which point ``method1`` would see 
 the child ``method2`` rather than the one in the parent.
Isn't that simply what I described as 'madness' above? One would seem to be exposing the Parent method to an unexpected code change, as one can not know what other Parent private state may be updated based upon the call to method2 being changed. That strikes me as causing non-determinism. I could see a use for this sort of thing: ```d struct Parent { void method1() { method3(); } void method2() { } void method3() { } } struct Child : Parent { override void method2() { method1(); } override void method3() { } } ``` Where the Child call from method2() to method1() invokes the Parent version, yet the Parent call from method1() to method3() will only ever invoke the Parent version. That means the behaviour of Parent stays consistent. To allow method3() to be redirected, is classful behaviour, and should not be forced upon an existing library of structs just because of what the child did. If one wants classes, use classes - as that sort of result is expected to be possible there.
Dec 04
parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 05/12/2024 6:22 AM, Derek Fawcus wrote:
     I want a way to reinterpret parent methods as if it was in the child
     if not overriden. At which point |method1| would see the child |
     method2| rather than the one in the parent.
 
 Isn't that simply what I described as 'madness' above?
 
 One would seem to be exposing the Parent method to an unexpected code 
 change, as one can not know what other Parent private state may be 
 updated based upon the call to method2 being changed.
 That strikes me as causing non-determinism.
 
 I could see a use for this sort of thing:
 
 |struct Parent { void method1() { method3(); } void method2() { } void 
 method3() { } } struct Child : Parent { override void method2() 
 { method1(); } override void method3() { } } |
 
 Where the Child call from method2() to method1() invokes the Parent 
 version, yet the Parent call from method1() to method3() will only ever 
 invoke the Parent version.
 
 That means the behaviour of Parent stays consistent. To allow method3() 
 to be redirected, is classful behaviour, and should not be forced upon 
 an existing library of structs just because of what the child did.
 
 If one wants classes, use classes - as that sort of result is expected 
 to be possible there.
You need this for things like serialization. Since we don't have runtime reflection it has to be done at CT, and if you have to do anything to offer it as a user, its just a NOPE compared to other languages. Its needed for both structs and classes.
Dec 04
parent reply Derek Fawcus <dfawcus+dlang employees.org> writes:
On Wednesday, 4 December 2024 at 21:49:02 UTC, Richard (Rikki) 
Andrew Cattermole wrote:
 You need this for things like serialization.
I'm not seeing that...
 Since we don't have runtime reflection it has to be done at CT, 
 and if you have to do anything to offer it as a user, its just 
 a NOPE compared to other languages.
Given that Go and Java use a form of UDA for assisting in serialisation, I don't see that the equivalent for D would be unacceptable. One either writes complex schemes for per structure callbacks, or one uses simple annotation with UDA. I know which I prefer, since it involves writing less code.
Dec 05
parent "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 06/12/2024 8:12 AM, Derek Fawcus wrote:
     Since we don't have runtime reflection it has to be done at CT, and
     if you have to do anything to offer it as a user, its just a NOPE
     compared to other languages.
 
 Given that Go and Java use a form of UDA for assisting in serialisation, 
 I don't see that the equivalent for D would be unacceptable.
 
 One either writes complex schemes for per structure callbacks, or one 
 uses simple annotation with UDA. I know which I prefer, since it 
 involves writing less code.
I've written many serialization like libraries in D using UDA's they are amazing. But you still need access to the child most type to do the introspection upon, and that in the case of classes means the user writing code for every child class.
Dec 05
prev sibling parent reply Derek Fawcus <dfawcus+dlang employees.org> writes:
On Tuesday, 3 December 2024 at 19:15:39 UTC, Derek Fawcus wrote:
 Personally, I'd rather have a struct like (POD) thing, even 
 with member functions, which does not allow for the possibility 
 of classful behaviour.  If classful behaviour is desired, then 
 somehow adjust classes so that they can be easily used as 
 non-reference types.
Also as I mentioned elsewhere, I don't like the idea of adding such to the betterC subset. If one wants classful behaviour in betterC, then I'd suggest somehow making classes work in betterC, and leaving structs without and possibility of classful stuff. That keeps more closely to the spirit of C, and without any of the Simula-67 like C-with-Classes stuff. Even then, I'd rather not have any form of classful behaviour (i.e. struct inheritance) in betterC, but that is obviously just my personal preference.
Dec 03
parent "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 04/12/2024 8:30 AM, Derek Fawcus wrote:
 If one wants classful behaviour in betterC, then I'd suggest somehow 
 making classes work in betterC, and leaving structs without and 
 possibility of classful stuff. That keeps more closely to the spirit of 
 C, and without any of the Simula-67 like C-with-Classes stuff.
C++ classes work in -betterC. Its not too difficult to implement down casting either. https://github.com/Project-Sidero/basic_memory/blob/main/source/sidero/base/allocators/classes.d I.e. https://github.com/Project-Sidero/fileformats/blob/master/source/sidero/fileformats/errors.d
Dec 03
prev sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Thursday, September 19, 2024 9:56:06 AM MST Richard Andrew Cattermole 
(Rikki) via dip.ideas wrote:
 As an idea this has come up in Razvan's DConf 2024 talk.

 1. Support inheritance on struct, for other structs.

 ```d
 struct Parent {
      ...
 }

 struct Child : Parent {
      ...
 }
 ```

 2. ``opDispatch`` function, may work in place of ``alias this``
 when no parent exists.

 ```d
 struct Parent {
      T thing;
      ref T opDispatch(string:"")() {
          return this.thing;
      }
 }

 struct Child : Parent {
 }

 Child child;
 T got = child;
 ```
After that talk, I discussed struct inheritance briefly with Walter, and his idea was that if we did it, there would be _no_ conversions of any kind that came from it. It would purely be a way to have a struct inherit all of the fields and member functions from the "parent" struct and as such would essentially be the compiler copying and pasting that code into the struct doing the inheriting. So, it would provide a way to inherit / copy the implementation, but the types would be completely divorced from one another in terms of how they were used. Personally, I think that that's the right approach, since it's the issues around implicit conversions that are the core problem with alias this, and it avoids all issues with regards to slicing objects (which is the primary reason why classes in D are on the heap instead of on the stack like they can be in C++). - Jonathan M Davis
Dec 05
next sibling parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 06/12/2024 11:41 AM, Jonathan M Davis wrote:
 On Thursday, September 19, 2024 9:56:06 AM MST Richard Andrew Cattermole
 (Rikki) via dip.ideas wrote:
 As an idea this has come up in Razvan's DConf 2024 talk.

 1. Support inheritance on struct, for other structs.

 ```d
 struct Parent {
       ...
 }

 struct Child : Parent {
       ...
 }
 ```

 2. ``opDispatch`` function, may work in place of ``alias this``
 when no parent exists.

 ```d
 struct Parent {
       T thing;
       ref T opDispatch(string:"")() {
           return this.thing;
       }
 }

 struct Child : Parent {
 }

 Child child;
 T got = child;
 ```
After that talk, I discussed struct inheritance briefly with Walter, and his idea was that if we did it, there would be _no_ conversions of any kind that came from it. It would purely be a way to have a struct inherit all of the fields and member functions from the "parent" struct and as such would essentially be the compiler copying and pasting that code into the struct doing the inheriting. So, it would provide a way to inherit / copy the implementation, but the types would be completely divorced from one another in terms of how they were used. Personally, I think that that's the right approach, since it's the issues around implicit conversions that are the core problem with alias this, and it avoids all issues with regards to slicing objects (which is the primary reason why classes in D are on the heap instead of on the stack like they can be in C++). - Jonathan M Davis
From my perspective that is mostly an implementation detail. The reason it is not fully an implementation detail is due to methods effectively having what I've been calling `` reinterpretAsChild`` turned on. We can still make overrides, and is expression to check if it inherits from the parent type to work. I'm ok with this approach. It simplifies a bunch of problems down.
Dec 05
parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Thursday, December 5, 2024 4:10:46 PM MST Richard (Rikki) Andrew Cattermole 
via dip.ideas wrote:
 After that talk, I discussed struct inheritance briefly with Walter, and
 his idea was that if we did it, there would be _no_ conversions of any
 kind that came from it. It would purely be a way to have a struct inherit
 all of the fields and member functions from the "parent" struct and as
 such would essentially be the compiler copying and pasting that code into
 the struct doing the inheriting.

 So, it would provide a way to inherit / copy the implementation, but the
 types would be completely divorced from one another in terms of how they
 were used.

 Personally, I think that that's the right approach, since it's the issues
 around implicit conversions that are the core problem with alias this, and
 it avoids all issues with regards to slicing objects (which is the primary
 reason why classes in D are on the heap instead of on the stack like they
 can be in C++).

 - Jonathan M Davis
From my perspective that is mostly an implementation detail. The reason it is not fully an implementation detail is due to methods effectively having what I've been calling `` reinterpretAsChild`` turned on. We can still make overrides, and is expression to check if it inherits from the parent type to work. I'm ok with this approach. It simplifies a bunch of problems down.
What isn't an implementation detail is that what Walter proposed would involve _zero_ conversions. So, there would be no casting to a parent from a child or vice versa unless you explicitly implemented casts for that. With what Walter was looking to do with struct inheritance, it would not be creating at type hierarchy at all. It would purely be a way to copy the implementation. So, there would nothing like reinterpretAsChild. The types would effectively be unrelated to one another as far as the type system was concerned. And if we _did_ have some sort of is expression to test whether one struct inherited from another, it couldn't be the same one that's used for classes, because there is no conversion (though honestly, the fact that we test for inheritance via implicit conversion with classes is broken given the fact that alias this exists). - Jonathan M Davis
Dec 05
parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 06/12/2024 1:14 PM, Jonathan M Davis wrote:
 On Thursday, December 5, 2024 4:10:46 PM MST Richard (Rikki) Andrew Cattermole
 via dip.ideas wrote:
 After that talk, I discussed struct inheritance briefly with Walter, and
 his idea was that if we did it, there would be _no_ conversions of any
 kind that came from it. It would purely be a way to have a struct inherit
 all of the fields and member functions from the "parent" struct and as
 such would essentially be the compiler copying and pasting that code into
 the struct doing the inheriting.

 So, it would provide a way to inherit / copy the implementation, but the
 types would be completely divorced from one another in terms of how they
 were used.

 Personally, I think that that's the right approach, since it's the issues
 around implicit conversions that are the core problem with alias this, and
 it avoids all issues with regards to slicing objects (which is the primary
 reason why classes in D are on the heap instead of on the stack like they
 can be in C++).

 - Jonathan M Davis
From my perspective that is mostly an implementation detail. The reason it is not fully an implementation detail is due to methods effectively having what I've been calling `` reinterpretAsChild`` turned on. We can still make overrides, and is expression to check if it inherits from the parent type to work. I'm ok with this approach. It simplifies a bunch of problems down.
What isn't an implementation detail is that what Walter proposed would involve _zero_ conversions. So, there would be no casting to a parent from a child or vice versa unless you explicitly implemented casts for that. With what Walter was looking to do with struct inheritance, it would not be creating at type hierarchy at all. It would purely be a way to copy the implementation. So, there would nothing like reinterpretAsChild. The types would effectively be unrelated to one another as far as the type system was concerned. And if we _did_ have some sort of is expression to test whether one struct inherited from another, it couldn't be the same one that's used for classes, because there is no conversion (though honestly, the fact that we test for inheritance via implicit conversion with classes is broken given the fact that alias this exists). - Jonathan M Davis
For the checking of inheritance what I mean is: ``is(Child : Parent)`` The same as a class has. Something the compiler certainly has the ability to offer. For casting, you could only do it via pointers in `` system`` code, you can do this today. No way would it be appropriate to add a new form of casting. Since there is no vtable or guarantee of heap allocation. As for `` reinterpretAsChild`` it would effectively be turned on and couldn't be opt-out, and would be a better way of describing this behavior as it would exist for classes. Rather than introducing some new unique to struct behavior. This needs a DIP written to make this stuff clear. So that'll be a next months job. Because I understand what you're saying and what Walter is concerned with based upon your statement. Its just that the spec and the implementation are going to have different concerns and they need to be aligned for both the end user and for it to be implementable.
Dec 05
parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Thursday, December 5, 2024 5:35:38 PM MST Richard (Rikki) Andrew Cattermole 
via dip.ideas wrote:
 For the checking of inheritance what I mean is:

 ``is(Child : Parent)``
Except that that _doesn't_ check for inheritance. It checks for an implicit conversion. It's just used for checking for inheritance based on the fact that a reference to a child class can implicitly convert to a reference of its parent class. It's already fundamentally broken in the sense that alias this can make it incorrect if you're testing for inheritance, e.g. ``` void main() { auto foo = new Foo; A a = foo; static assert(is(Foo : A)); } class A {} class Foo { A a; alias this = a; } ``` Really, we need something in __traits to test for inheritance and to stop using is expressions for it. Either way, it's fundamentally wrong to have is(Child : Parent) tell you that a struct named Child inherits from a struct named Parent, because they wouldn't have an implicit conversion, and : is testing specifically for an implicit conversion. - Jonathan M Davis
Dec 05
next sibling parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 06/12/2024 2:04 PM, Jonathan M Davis wrote:
 On Thursday, December 5, 2024 5:35:38 PM MST Richard (Rikki) Andrew Cattermole
 via dip.ideas wrote:
 For the checking of inheritance what I mean is:

 ``is(Child : Parent)``
Except that that _doesn't_ check for inheritance. It checks for an implicit conversion. It's just used for checking for inheritance based on the fact that a reference to a child class can implicitly convert to a reference of its parent class. It's already fundamentally broken in the sense that alias this can make it incorrect if you're testing for inheritance, e.g. ``` void main() { auto foo = new Foo; A a = foo; static assert(is(Foo : A)); } class A {} class Foo { A a; alias this = a; } ``` Really, we need something in __traits to test for inheritance and to stop using is expressions for it. Either way, it's fundamentally wrong to have is(Child : Parent) tell you that a struct named Child inherits from a struct named Parent, because they wouldn't have an implicit conversion, and : is testing specifically for an implicit conversion. - Jonathan M Davis
Problem is, template parameters also should work, using ``Child : Parent`` syntax. Otherwise the usability on this is going to be absolutely atrocious in meta-programming.
Dec 05
parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Thursday, December 5, 2024 6:13:04 PM MST Richard (Rikki) Andrew Cattermole 
via dip.ideas wrote:
 Problem is, template parameters also should work, using ``Child :
 Parent`` syntax.

 Otherwise the usability on this is going to be absolutely atrocious in
 meta-programming.
: tests for implicit conversions. That's all it ever does, and making it do anything else will introduce inconsistencies into the language. For instance, since struct inheritance would _not_ involve an implicit conversion, how would you test for an implicit conversion if is(T : U) were true because T inherited from U? After all, since we're unfortunately not actually going to get rid of alias this, it would be quite possible to have T inherit from U an then have an alias this which makes it implicitly convert to U. Code that wants to test for struct inheritance can do so with a template constraint and a __traits trait just like plenty of other code does. There's nothing special about inheritance, let alone struct inheritance that makes it any different. Also, honestly, I don't think that testing for struct inheritance with metaprogramming is even likely to be a valid use case outside of niche situations. There is no conversion unless the programmer explicitly adds one, so a "child" type can't be treated as if it were the same as its "parent" type, and if templated code wants to use the API of the parent struct so that it works with any struct type that's derived from it, it's arguably better to test its API and not anything inheritance-related, because it's the API that actually matters for using it, not whether that API was inherited from a particular struct. And if it's the API that's tested, then it can work with any type with that API regardless of whether it's derived from a particular struct. Really, if struct inheritance does not involve implicit conversion, then I don't think that there's much reason to even care that that relationship exists. They're just two types which happen to have some of the same members, and if they need to be used by the same code, it's going to need to be templated just like happens with any two unrelated types which share enough of the same API to be duck typed together. And there's no need to take the inheritance into account at all with that code. It's simply the API that matters, not where the implementation happens to have come from. Either way, given that : is specifically for testing implicit conversions, it's really not appropriate to conflate it with inheritance when implict conversions aren't involved. And even for class inheritance, which has the implicit conversion, it's arguably a mistake to use it to test for inheritance, because it's testing for an implicit conversion, not inheritance, and the implicit conversion can be there for other reasons. So, in general, we should be moving away from using is(T : U) to test for inheritance of any kind, not making struct inheritance use it too. - Jonathan M Davis
Dec 05
parent "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
I suppose we could do > and < comparison of types in template parameters 
and is expressions.

Which could be hierarchy based instead of implicit conversions.

I would need to double check it, but ok I can ditch the : in favor of > 
here.
Dec 05
prev sibling parent reply Nick Treleaven <nick geany.org> writes:
On Friday, 6 December 2024 at 01:04:37 UTC, Jonathan M Davis 
wrote:
 class A {}

 class Foo
 {
     A a;

     alias this = a;
 }
 ```
Deprecating that was attempted: https://dlang.org/changelog/2.103.0.html#dmd.deprecate-alias-this-for-classes Is deprecation/removal planned for a future edition?
Dec 06
parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Friday, December 6, 2024 4:42:14 AM MST Nick Treleaven via dip.ideas wrote:
 On Friday, 6 December 2024 at 01:04:37 UTC, Jonathan M Davis

 wrote:
 class A {}

 class Foo
 {

     A a;

     alias this = a;

 }
 ```
Deprecating that was attempted: https://dlang.org/changelog/2.103.0.html#dmd.deprecate-alias-this-for-classe s Is deprecation/removal planned for a future edition?
Walter seems to think that we cannot remove alias this, but he's quite averse to removing anything at this point, because he's paranoid about breaking code and just generally seems to be against deprecating anything. I don't know what he'll be willing to consider when it comes to alias this and editions. At present, I don't think that much of anything is actually planned for editions in terms of what we're going to change. Ideas have been bandied around, and Walter should be more amenable to breaking changes with editions (since that's at least partially the idea behind them), but we'll have to see what actually happens. - Jonathan M Davis
Dec 06
prev sibling parent reply Derek Fawcus <dfawcus+dlang employees.org> writes:
On Thursday, 5 December 2024 at 22:41:25 UTC, Jonathan M Davis 
wrote:
 After that talk, I discussed struct inheritance briefly with 
 Walter, and his idea was that if we did it, there would be _no_ 
 conversions of any kind that came from it. It would purely be a 
 way to have a struct inherit all of the fields and member 
 functions from the "parent" struct and as such would 
 essentially be the compiler copying and pasting that code into 
 the struct doing the inheriting.

 So, it would provide a way to inherit / copy the 
 implementation, but the types would be completely divorced from 
 one another in terms of how they were used.

 Personally, I think that that's the right approach, since it's 
 the issues around implicit conversions that are the core 
 problem with alias this, and it avoids all issues with regards 
 to slicing objects (which is the primary reason why classes in 
 D are on the heap instead of on the stack like they can be in 
 C++).
So if I read that correctly, for the latter code example I gave, assuming use of structs rather and classes, and adjusted... The 'Assign' case would be a compile error, and once removed it would yield: ``` MethB(P) Direct Parent MethC(P) Direct Parent MethB(P) Inherit Child MethC(C) Inherit Child ``` Is that correct? Also is it the case that method overrides would dominate over any 'pasted' method from the parent - i.e. the MethC case? Or would those be forbidden as a name conflict? Presumably one could not have data fields with the same name in the Parent and Child, or would there be a rule for resolving that conflict?
Dec 05
parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Thursday, December 5, 2024 4:36:17 PM MST Derek Fawcus via dip.ideas wrote:
 On Thursday, 5 December 2024 at 22:41:25 UTC, Jonathan M Davis

 wrote:
 After that talk, I discussed struct inheritance briefly with
 Walter, and his idea was that if we did it, there would be _no_
 conversions of any kind that came from it. It would purely be a
 way to have a struct inherit all of the fields and member
 functions from the "parent" struct and as such would
 essentially be the compiler copying and pasting that code into
 the struct doing the inheriting.

 So, it would provide a way to inherit / copy the
 implementation, but the types would be completely divorced from
 one another in terms of how they were used.

 Personally, I think that that's the right approach, since it's
 the issues around implicit conversions that are the core
 problem with alias this, and it avoids all issues with regards
 to slicing objects (which is the primary reason why classes in
 D are on the heap instead of on the stack like they can be in
 C++).
So if I read that correctly, for the latter code example I gave, assuming use of structs rather and classes, and adjusted... The 'Assign' case would be a compile error, and once removed it would yield: ``` MethB(P) Direct Parent MethC(P) Direct Parent MethB(P) Inherit Child MethC(C) Inherit Child ``` Is that correct?
The types would be completely independent from one another. It would just be a way to copy the implementation from one to the other. So, no conversions or assignments would ever take place without some explicit code handling it, just like normally occurs with any two types which have nothing to do with one another. It's purely an inheritance of implementation and would not create a hierarchy like you get with classes. So, it would therefore avoid all of the various issues that you get with class inheritance and objects on the stack in C++ - but it also wouldn't get any form of polymorphism. It would just be a way to share code.
 Also is it the case that method overrides would dominate over any
 'pasted' method from the parent - i.e. the MethC case?  Or would
 those be forbidden as a name conflict?
IIRC, from what Walter said, if the child implemented the same member function as the parent, the child's would take precedence, and the parent's would basically not exist in the child.
 Presumably one could not have data fields with the same name in
 the Parent and Child, or would there be a rule for resolving that
 conflict?
I didn't discuss that particular issue with Walter, so I don't know what his stance would be, but the most obvious thing would presumably be to just make it illegal. Particularly when you're dealing with private members, it's not like it would be a big deal to just name the member variable something else to avoid the conflict. We had a fairly quick discussion on some of the obvious issues that I thought of off the top of my head (e.g. conversions and object slicing), but it's not like we sat down and hashed it all out in detail. So, if/when Walter decides to implement it, he'll have to sort that out with a DIP (or he'll have to approve someone else's DIP where they provide all of those details). But the discussion _was_ enough to make it clear that Walter's intention was to use struct inheritance purely as a way to inherit the implementation and _not_ as a way to provide any sort of implicit conversions or a way to use one type as another (though templated code could use duck typing like it normally does to work with types that have the appropriate API, so you could have the same code work with multiple struct types that inherited from the same parent, since they'd all have the API from the parent). - Jonathan M Davis
Dec 05
parent reply claptrap <clap trap.com> writes:
On Friday, 6 December 2024 at 00:06:12 UTC, Jonathan M Davis 
wrote:
 On Thursday, December 5, 2024 4:36:17 PM MST Derek Fawcus via
 Is that correct?
The types would be completely independent from one another. It would just be a way to copy the implementation from one to the other.
Yay! This will be the new "private is not private" topic. I expect a deluge of ****posting complaining that struct inheritance is not inheritance.
Dec 06
parent Derek Fawcus <dfawcus+dlang employees.org> writes:
On Friday, 6 December 2024 at 12:21:02 UTC, claptrap wrote:
 On Friday, 6 December 2024 at 00:06:12 UTC, Jonathan M Davis 
 wrote:
 On Thursday, December 5, 2024 4:36:17 PM MST Derek Fawcus via
 Is that correct?
The types would be completely independent from one another. It would just be a way to copy the implementation from one to the other.
Yay! This will be the new "private is not private" topic. I expect a deluge of ****posting complaining that struct inheritance is not inheritance.
Then maybe don't refer to it as "struct inheritance", possibly use something like "struct inclusion", or "struct addition". Plus maybe a different syntax, e.g.: ```d struct A { } struct B += A { } ```
Dec 06