On 06/19/2016 11:19 PM, Joerg Joergonson wrote:
On Sunday, 19 June 2016 at 20:21:35 UTC, ag0aep6g wrote:
[...]
No. B!b is derived from A!b, not from A!a. `b` being derived from `a`
does not make A!b derived from A!a.

why not? This doesn't seem logical!

Template parameters simply don't work like that. A template can result in completely unrelated types based on template parameters.

For example:

    template C(T)
    {
        static if (is(T == A)) class C {}
        else static if(is(T == B)) alias C = int;
        else struct C {int x;}
    }

As you see there can't be any inheritance relation between the different instantiations of the C template here. Having such a relation for different instantiation that result in classes would be a weird special case.

There's probably a really simple and obvious reason why that special would be a bad idea in itself, but I'm not able to point it out. Maybe make a thread in the General group. I think the language people tend to focus their attention there.

Criticism and improvement proposals are also better directed to the General group.

Here is the full inheritance tree:

X
├─x
│ └─a
│   └─b
├─A!a
└─A!b
  └─B!b


But b is derived from a.

Yeah, that's right there in the middle.

Your tree completely ignores under A.

Clearly, there's B!b under A!b. That's it. Nothing exists below B!b. B!a doesn't exist either. A!a is on a different branch. I don't think I've missed anything.

[...]
Just because D doesn't understand this logical consistency between
inheritance doesn't mean D is right. (Hence, why D's type system is broke)


In fact, the tree should look like this:

X
├─x
│ └─a
│   └─b
└─A!x
     │  \
     └─A!a
       │  \
       └─A!b
         │  \
         └─B!b

I'm having trouble reading this. A!x isn't valid, as the constraint on A says `T : a`, but x doesn't satisfy that.

I also don't understand what the backslashes mean. They just repeat the other lines, don't they? Or do they connect x, a, and b? That's already expressed in the upper section.

As for A!b being below A!a, I can only repeat that this inheritance is not implied. You would have to spell it out explicitly for the compiler to pick it up.

Basically you are treating A!a and A!b as if a and be have no
relationship. BUT THEY DO!

Well, to the compiler they don't.

If you don't take that into account then your
wrong.

Simply stating how D behaves is not proof of why it is right or wrong.

For discussions about how D should behave, please post to General. Here in the Learn group I (and I think we) tend to focus on how D works or is meant to work. The way you think it should behave here is not how it's meant to work by the designers and implementors.

[...]
import std.stdio;
class a { }
class b : a { }

class A(T : a)
{
    T x;
}



void main(string[] argv)
{
     auto _A = new A!a();
     auto _C = new A!b();

     auto p = cast(A!a)_C;
}

p is null. My example with B is irrelevant. The issue is with the
parameter.

As you can see, D thinks that A!b and A!a are completely unrelated... as
do you and arsd.

Do you seriously think this is the case? That

class b : a { }

and

class b { }

effectively mean the same with regards to A?

Yes. A!a is a class like this: `class A!a {a x;}`. A!b is this: `class A!b {b x;}`. The generated classes have members that have an inheritance relationship, but that doesn't imply an inheritance relationship between A!a and A!b.

The whole problem comes about at this line:

auto p = cast(A!a)_C;

We are trying to cast `T x` in C, which is effectively `b x` to `a x`.

No. You try to cast from one class type to another, that's different from casting the members.

You can have two classes with exactly the same members, yet they're not (directly) castable to each other when there's no inheritance relation:

    class A {int x;}
    class B {int x;}
    void main()
    {
        assert((cast(B) new A) is null); /* holds */
        assert((cast(A) new B) is null); /* holds */
    }

Maybe this is the crux? I'd expect you to be of the opinion that those casts should work.

Of course, you can force an unsafe conversion by casting to void* first:

    cast(B) cast(void*) new A

A reinterpret-style cast would also work:

    A a = new A;
    B b = * cast(B*) &a;

I suppose a simple cast doesn't do that because it's deemed more useful to get null when the inheritance doesn't work out, even when the member layout would work out. This way `cast` can be used for downcasts in a safe manner.

Because, when there is no inheritance relation, that means there is no guarantee that a class can be used in place of another one, even when the fields are compatible. Consider A and B having methods with the same name that do completely unrelated things. Converting accidentally from one to the other would be bad.

Reply via email to