Re: reimplementing an interface in a derived class

2019-01-09 Thread Heromyth via Digitalmars-d-learn

On Thursday, 3 January 2019 at 23:23:12 UTC, Neia Neutuladh wrote:

On Thu, 03 Jan 2019 22:30:48 +, kdevel wrote:

class A : D {
 int foo() { return 1; }
}

class B : A, D {
[...]

What is the meaning of the ", D"? It does not seem to make a 
difference if it is omitted.


B must provide its own implementation of D. It can't simply use 
A's implementation.


As for class B, it has already included foo(), even if it doesn't 
override this method. So, is it necessary to override it again? 
It not always needed to override foo(). Sometimes, we just want 
to keep it as the one in class A and override it as necessary. 
Honestly hope that the compiler can do this.


Re: reimplementing an interface in a derived class

2019-01-07 Thread Steven Schveighoffer via Digitalmars-d-learn

On 1/4/19 7:16 PM, kdevel wrote:

On Friday, 4 January 2019 at 20:21:56 UTC, Steven Schveighoffer wrote:

missing in the source. But why is d a null reference in the first place?


Because when you dynamically cast one object or interface to another 
object or interface, and that result is not possible (if you remove 
",D" from the example you quoted, then neither A nor B implement D), 
then the result is null.


I overlooked that Alex wrote

    class A

and not

    class A : D

which I came across in the examples in #10 and #11 of

    https://dlang.org/spec/interface.html

and to which I referred to in my OP.


https://dlang.org/spec/expression.html#cast_expressions

See parts 2 and 3.


    part 2
    "Any casting of a class reference to a derived class reference
    is done with a runtime check to make sure it really is a downcast.
    null is the result if it isn't."

Part 2 is about downcasting. Does that apply here? 


Yes. If the requested interface or class isn't a base class, or a base 
interface, then a downcast must be involved. Essentially the downcast is 
a runtime check to see if this class instance actually is a derived one, 
or a derived class implements the specified interface. D does not have 
multiple inheritance.



Due to the omission
of ": D" in Alex' example the cast is not a cast "to a derived class
reference" and hence this part does not apply.


Of course it applies :) The fact that the class is not an instance of D 
in a derived class means that it returns null. The spec statement could 
be worded better.



OTOH upcasting is also
not covered by part 2 and seems to be legal:


Upcasting is trivial, and the compiler will not even spend time doing a 
runtime check, it knows how to do this at compile time. It doesn't even 
require a cast.


Just like casting a short to an int doesn't require a cast, but you are 
free to put one in if you like.


-Steve


Re: reimplementing an interface in a derived class

2019-01-04 Thread kdevel via Digitalmars-d-learn
On Friday, 4 January 2019 at 20:21:56 UTC, Steven Schveighoffer 
wrote:
missing in the source. But why is d a null reference in the 
first place?


Because when you dynamically cast one object or interface to 
another object or interface, and that result is not possible 
(if you remove ",D" from the example you quoted, then neither A 
nor B implement D), then the result is null.


I overlooked that Alex wrote

   class A

and not

   class A : D

which I came across in the examples in #10 and #11 of

   https://dlang.org/spec/interface.html

and to which I referred to in my OP.


https://dlang.org/spec/expression.html#cast_expressions

See parts 2 and 3.


   part 2
   "Any casting of a class reference to a derived class reference
   is done with a runtime check to make sure it really is a 
downcast.

   null is the result if it isn't."

Part 2 is about downcasting. Does that apply here? Due to the 
omission
of ": D" in Alex' example the cast is not a cast "to a derived 
class
reference" and hence this part does not apply. OTOH upcasting is 
also

not covered by part 2 and seems to be legal:

part 2 at its face value:
```part2.d
import std.stdio;

class A {
   void foo () { __FUNCTION__.writeln; }
}

class B : A {
   override void foo () { __FUNCTION__.writeln; }
}

void main ()
{
   auto x = new B;
   auto u = cast (A) x;
   typeof (u).stringof.writeln;
   u.foo;
}
```
$ ./part2
A
part2.B.foo




Re: reimplementing an interface in a derived class

2019-01-04 Thread Ali Çehreli via Digitalmars-d-learn

On 01/04/2019 01:08 PM, Ali Çehreli wrote:

> There is only one vtbl per class object

Correcting myself after reading Neia Neutuladh's post: I should have 
said "There is only one vtbl per class type". Every class object has a 
vtbl pointer that points at its type's vtbl.


So, it's normally two pointer hops to execute a virtual function:

1) Get the object's vtbl pointer to reach the vtbl of that type; pseudo 
code:


  v = o.vtbl_ptr

2) Get the function pointer from a slot in that table (assuming foo() 
happens to be at index 5); pseudo code:


  f = v[5]  // This must be a generic type like void*

3) Call the function by passing arguments; pseudo code:

  alias F = TheActualTypeOfTheMemberFunction;
  (cast(F)f)(42, "hello", ...)

Ali



Re: reimplementing an interface in a derived class

2019-01-04 Thread Alex via Digitalmars-d-learn

On Friday, 4 January 2019 at 21:47:59 UTC, Neia Neutuladh wrote:

On Fri, 04 Jan 2019 08:46:24 +, Alex wrote:
Let's assume this is right. How to force a B object to behave 
like an A object? I thought casting is a possible approach...


It requires a bit of surgery:


:)



import std.stdio;
class A
{
void foo() { writeln("hello from A!"); }
}
class B : A
{
override void foo() { writeln("hello from B!"); }
}
void main()
{
auto b = new B;
auto ptrB = cast(void**)b;
ptrB[0] = A.classinfo.vtbl.ptr;
b.foo();
}

This takes advantage of the object layout used by DMD. 'vtbl' 
is the virtual function table, which is basically an array of 
function pointers. Each member function defined in a type (and 
its super types) gets a unique index into that array.


So when you write:

b.foo();

That works out to:

(cast(void function(B))b.vtbl[5])(b);

We replace object b's vtbl with class A's, and now b is just an 
A with some extra stuff allocated in its memory block.


Don't do this in production code. This is a terrible thing to 
do in production code, or any code you intend to use other than 
to see how D's object model works.


I see... That's cool nevertheless!


Re: reimplementing an interface in a derived class

2019-01-04 Thread Alex via Digitalmars-d-learn

On Friday, 4 January 2019 at 21:08:24 UTC, Ali Çehreli wrote:

[...]
In this case, casting is using the B object through it's A 
interface. The overridden behavior does not change.


Yeah... This was my mistake.

(Actually, that is possible in languages that support multiple 
inheritance through multiple virtual function pointer tables 
(vtbl) but D does not support that.)


Although I'm getting into implementation details here, I think 
it helps with understanding the semantics. There is only one 
vtbl per class object in D and the function entries are all 
filled in during construction. So, a B object's 'foo' slot in 
that table is filled with B.foo. So, such an object can foo() 
only as a B.


Nice :)


[...]


By the way, do you have a use case in mind? Perhaps there are 
other ways to achieve that.


Well, not really. I was just astonished that casting is not _the_ 
forge tool. Then, I checked, that the type indeed changes and 
wondered why the behavior was still from the object before 
casting.


But I assume, as in an A-type an A object, as well as a B object, 
can be stored, and the creation is under my own control - a use 
case would be some corner case... And the default virtual 
definition explains the behavior very well...


Re: reimplementing an interface in a derived class

2019-01-04 Thread Neia Neutuladh via Digitalmars-d-learn
On Fri, 04 Jan 2019 08:46:24 +, Alex wrote:
> Let's assume this is right. How to force a B object to behave like an A
> object? I thought casting is a possible approach...

It requires a bit of surgery:

import std.stdio;
class A
{
void foo() { writeln("hello from A!"); }
}
class B : A
{
override void foo() { writeln("hello from B!"); }
}
void main()
{
auto b = new B;
auto ptrB = cast(void**)b;
ptrB[0] = A.classinfo.vtbl.ptr;
b.foo();
}

This takes advantage of the object layout used by DMD. 'vtbl' is the 
virtual function table, which is basically an array of function pointers. 
Each member function defined in a type (and its super types) gets a unique 
index into that array.

So when you write:

b.foo();

That works out to:

(cast(void function(B))b.vtbl[5])(b);

We replace object b's vtbl with class A's, and now b is just an A with 
some extra stuff allocated in its memory block.

Don't do this in production code. This is a terrible thing to do in 
production code, or any code you intend to use other than to see how D's 
object model works.


Re: reimplementing an interface in a derived class

2019-01-04 Thread Ali Çehreli via Digitalmars-d-learn

On 01/04/2019 12:46 AM, Alex wrote:
> On Friday, 4 January 2019 at 07:37:43 UTC, bauss wrote:
>> No, because you OVERRIDE A's foo().
>>
>> A does not exist. A is B and when you cast B to A you just tell the
>> compiler that the reference should only have A's signature available.
>>
>> You're not assigning B to A.
>
> Let's assume this is right. How to force a B object to behave like an A
> object?

Not possible by default. However, a B object is already behaving like an 
A object because e.g. it overrides the foo() member function.


> I thought casting is a possible approach...

In this case, casting is using the B object through it's A interface. 
The overridden behavior does not change. (Actually, that is possible in 
languages that support multiple inheritance through multiple virtual 
function pointer tables (vtbl) but D does not support that.)


Although I'm getting into implementation details here, I think it helps 
with understanding the semantics. There is only one vtbl per class 
object in D and the function entries are all filled in during 
construction. So, a B object's 'foo' slot in that table is filled with 
B.foo. So, such an object can foo() only as a B.


If there is such a need and B can indeed support behaving like an A, it 
can do so itself by calling A.foo, not through vtbl, but directly:


class B : A {
  override void foo() {
A.foo();  // Calling directly
  }
}

By the way, do you have a use case in mind? Perhaps there are other ways 
to achieve that.


Ali



Re: reimplementing an interface in a derived class

2019-01-04 Thread Steven Schveighoffer via Digitalmars-d-learn

On 1/4/19 2:55 PM, kdevel wrote:

On Friday, 4 January 2019 at 11:27:59 UTC, Alex wrote:

On Friday, 4 January 2019 at 09:58:59 UTC, bauss wrote:


[...]


As for the OP, I think here the usefulness of ", D" should be visible:


[...]


class B : A, D
{
    override int foo() { return 2; }
}


[...]


    D d = cast(D) b;
    assert(d.foo == 2); // returns 2


If I remove the ", D" the program segfaults in this line:

Program received signal SIGSEGV, Segmentation fault.
0x0042c184 in D main () at ggg.d:26
26    d.foo();
(gdb) p d
$1 = (ggg.D *) 0x0

There is clearly an

    assert (d);

missing in the source. But why is d a null reference in the first place?


Because when you dynamically cast one object or interface to another 
object or interface, and that result is not possible (if you remove ",D" 
from the example you quoted, then neither A nor B implement D), then the 
result is null.


https://dlang.org/spec/expression.html#cast_expressions

See parts 2 and 3.

-Steve


Re: reimplementing an interface in a derived class

2019-01-04 Thread kdevel via Digitalmars-d-learn

On Friday, 4 January 2019 at 11:27:59 UTC, Alex wrote:

On Friday, 4 January 2019 at 09:58:59 UTC, bauss wrote:


[...]

As for the OP, I think here the usefulness of ", D" should be 
visible:


[...]


class B : A, D
{
override int foo() { return 2; }
}


[...]


D d = cast(D) b;
assert(d.foo == 2); // returns 2


If I remove the ", D" the program segfaults in this line:

Program received signal SIGSEGV, Segmentation fault.
0x0042c184 in D main () at ggg.d:26
26  d.foo();
(gdb) p d
$1 = (ggg.D *) 0x0

There is clearly an

   assert (d);

missing in the source. But why is d a null reference in the first 
place?


Re: reimplementing an interface in a derived class

2019-01-04 Thread Alex via Digitalmars-d-learn

On Friday, 4 January 2019 at 09:58:59 UTC, bauss wrote:

On Friday, 4 January 2019 at 09:53:18 UTC, Alex wrote:
I assume the move method of an Animal is not abstract, and 
therefore I supposed, casting to this type explicitly should 
restore this very non-abstract behavior. But this is not the 
case.
And the final/virtual thing above explains this to some 
extent, too... I think...


A cast is only a way to tell the compiler the signature of a 
type.


In most cases it actually does nothing at runtime and is just a 
way to help the compiler.


Ex.
auto b = new B;
auto a = cast(A)b;

Will just tell the compiler that all usage of a will be 
restricted to the signature of A.
It doesn't tell the compiler that all usage of a should be the 
same as A.


At runtime it would actually just be:
auto b = new B;
auto a = b; //*


* The last line is thought to be restricted to the signature of 
A, but the behavior of B.


Yeah... I think this is a matter of habituation. I assumed 
casting is something more powerful and overcomes the virtuality 
of functions if their body exists. But its the other way round. 
Thanks for the clarification.


As for the OP, I think here the usefulness of ", D" should be 
visible:


´´´
interface D
{
int foo();
final int fun(){ return 42; }
}

class A
{
//size_t dummy;
int foo() { return 1; }
int fun() { return 72; }
}

class B : A, D
{
override int foo() { return 2; }
}

void main()
{
B b = new B();
assert(b.foo == 2); // returns 2
assert(b.fun == 72);// fun returns 72, as defined 
in A


D d = cast(D) b;
assert(d.foo == 2); // returns 2
assert(d.fun == 42);// fun returns 42, as defined 
in D


A a = cast(A) b;
assert(a.foo == 2); // returns 2, as it remains B
assert(a.fun == 72);// fun returns 72, as defined 
in A


D d2 = cast(D) a;
assert(d2.foo == 2);// returns 2, as it remains B
assert(d2.fun == 42);   // fun returns 42, as defined 
in D


A a2 = new A();
assert(a2.foo == 1);// returns 1, as defined in A
assert(a2.fun == 72);   // returns 72, as defined in A
assert((cast(D) a2) is null);   // not castable to D
}
´´´


Re: reimplementing an interface in a derived class

2019-01-04 Thread bauss via Digitalmars-d-learn

On Friday, 4 January 2019 at 09:53:18 UTC, Alex wrote:
I assume the move method of an Animal is not abstract, and 
therefore I supposed, casting to this type explicitly should 
restore this very non-abstract behavior. But this is not the 
case.
And the final/virtual thing above explains this to some extent, 
too... I think...


A cast is only a way to tell the compiler the signature of a type.

In most cases it actually does nothing at runtime and is just a 
way to help the compiler.


Ex.
auto b = new B;
auto a = cast(A)b;

Will just tell the compiler that all usage of a will be 
restricted to the signature of A.
It doesn't tell the compiler that all usage of a should be the 
same as A.


At runtime it would actually just be:
auto b = new B;
auto a = b;


Re: reimplementing an interface in a derived class

2019-01-04 Thread Alex via Digitalmars-d-learn

On Friday, 4 January 2019 at 09:30:32 UTC, bauss wrote:
Your C++ example is not the same as in D because in C++ 
functions aren't virtual by default, they are in D.


Mark your functions as virtual in your C++ example and see what 
happens.


All functions in D are virtual by default!


Yep. Got it! Thanks :)


Re: reimplementing an interface in a derived class

2019-01-04 Thread Alex via Digitalmars-d-learn

On Friday, 4 January 2019 at 09:19:48 UTC, Simen Kjærås wrote:

On Friday, 4 January 2019 at 08:40:04 UTC, Alex wrote:

class A
{
public:
int foo(){return 1;}
};
class B : public A
{
public:
int foo(){return 2;}
};


In C++, methods are non-virtual by default. In D, they are 
virtual by default. Because of this, the two examples are 
different. In fact, D disallows overriding non-virtual, 
non-private functions, as specified in 
https://dlang.org/spec/function.html#virtual-functions. For 
private functions it does work, though:




Ha... got it!
Because final methods are allowed in interfaces, maybe this is 
the answer to the OP...



class A {
private final int foo() { return 1; }
}
class B : A {
final int foo() { return 2; }
}

unittest {
assert((new A).foo == 1);
assert((new B).foo == 2);
assert((cast(A)(new B)).foo == 1);
}

Imagine you give me a box with an Animal in it. You know it's a 
Bird, but I only know it's an Animal of some kind.


Case 1: I tell it to move() to the top of a tree. Would you 
expect it to climb or fly?
(let's not get into penguins and other flightless birds right 
now, the OOP animal metaphor is strained enough as it is)


Case 1 is overriding - Bird has defined how move() should work, 
and it will do that even if you only know it's an animal of 
some kind.


This can be exemplified in D as:

import std.stdio : writeln;

abstract class Animal {
abstract void move();
}

class Bird : Animal {
override void move() {
writeln("Flying.");
}
}


unittest {
(new Bird).move(); // Flying
(cast(Animal)new Bird).move(); // Flying
}

--
  Simen


Case 2 is clear. I was wondering about the behavior in case 1: 
not because of the override behavior, but because there is an 
explicit cast in between.
I assume the move method of an Animal is not abstract, and 
therefore I supposed, casting to this type explicitly should 
restore this very non-abstract behavior. But this is not the case.
And the final/virtual thing above explains this to some extent, 
too... I think...


Re: reimplementing an interface in a derived class

2019-01-04 Thread bauss via Digitalmars-d-learn

On Friday, 4 January 2019 at 08:40:04 UTC, Alex wrote:

On Friday, 4 January 2019 at 02:13:27 UTC, Neia Neutuladh wrote:
I can't think of a single class system that works like that. 
C++, Java, C#, Dart, and TypeScript all work like D here. 
GObject in C works like D.


In the example below, the "2" of B.foo is printed only once. 
Independently of the cast type, after degrading a B to an A the 
degraded object behaves like an A.


´´´ C++ ´´´
#include 
class A
{
public:
int foo(){return 1;}
};
class B : public A
{
public:
int foo(){return 2;}
};

void performFoo(A *a)
{
std::cout << a->foo() << std::endl;
}

int main() {
auto a = new A();
auto b = new B();
std::cout << a->foo() << std::endl;
std::cout << b->foo() << std::endl;
std::cout << dynamic_cast(b)->foo() << std::endl;
std::cout << static_cast(b)->foo() << std::endl;
std::cout << reinterpret_cast(b)->foo() << std::endl;
performFoo(a);
performFoo(b);
return 0;
}
´´´
The point of OOP is that a bundle of data has particular ways 
of dealing with it. B has different data (at least 
theoretically), and that data has different ways of working 
with it. So if casting to a base class changed something to 
use the base class's behavior, you'd get bugs almost anywhere 
you used inheritance, since the derived class's data isn't 
being modified properly.


Now I have the feeling, I'm missing something elementary... 
sorry for this...
But take the classic example of OOP of an Animal and a Dog: 
Animal.

Let the animal implement some default move and eat behavior.
Let the dog override the move method and implement bark.
If you degrade the dog to the animal by casting it should still 
be able to move and eat, but not bark.


This should always be true for inherited objects as the base 
classes define enough content to manage proper behavior of 
their own. (Given they are not abstract, a function is not 
virtual and so on...)


Your C++ example is not the same as in D because in C++ functions 
aren't virtual by default, they are in D.


Mark your functions as virtual in your C++ example and see what 
happens.


All functions in D are virtual by default!


Re: reimplementing an interface in a derived class

2019-01-04 Thread Simen Kjærås via Digitalmars-d-learn

On Friday, 4 January 2019 at 08:40:04 UTC, Alex wrote:

class A
{
public:
int foo(){return 1;}
};
class B : public A
{
public:
int foo(){return 2;}
};


In C++, methods are non-virtual by default. In D, they are 
virtual by default. Because of this, the two examples are 
different. In fact, D disallows overriding non-virtual, 
non-private functions, as specified in 
https://dlang.org/spec/function.html#virtual-functions. For 
private functions it does work, though:


class A {
private final int foo() { return 1; }
}
class B : A {
final int foo() { return 2; }
}

unittest {
assert((new A).foo == 1);
assert((new B).foo == 2);
assert((cast(A)(new B)).foo == 1);
}

Now I have the feeling, I'm missing something elementary... 
sorry for this...
But take the classic example of OOP of an Animal and a Dog: 
Animal.

Let the animal implement some default move and eat behavior.
Let the dog override the move method and implement bark.
If you degrade the dog to the animal by casting it should still 
be able to move and eat, but not bark.



Imagine you give me a box with an Animal in it. You know it's a 
Bird, but I only know it's an Animal of some kind.


Case 1: I tell it to move() to the top of a tree. Would you 
expect it to climb or fly?
(let's not get into penguins and other flightless birds right 
now, the OOP animal metaphor is strained enough as it is)


Case 2: I try to tell it to bark(), but there's no way to do 
that, because I have access to it as an Animal, not a Dog.
Cutting off its beak and gluing a muzzle there (casting a Bird to 
a Dog) will only lead to suffering.


Case 1 is overriding - Bird has defined how move() should work, 
and it will do that even if you only know it's an animal of some 
kind. Case 2 is subclassing - a Dog can do things that the 
average Animal can't, and this is reflected in it having a wider 
interface - more methods.


This can be exemplified in D as:

import std.stdio : writeln;

abstract class Animal {
abstract void move();
}

class Bird : Animal {
override void move() {
writeln("Flying.");
}
}

class Dog : Animal {
override void move() {
writeln("Walking."); // Assume this is not Muttley
}
void bark() {
writeln("Woof!");
}
}

unittest {
(new Bird).move(); // Flying
(cast(Animal)new Bird).move(); // Flying
//(cast(Animal)new Bird).bark(); // Fails to compile - 
generic animals can't bark
(cast(Dog)new Bird).bark(); // Crashes because a Bird is not 
a Dog, cast returns null.

}

--
  Simen


Re: reimplementing an interface in a derived class

2019-01-04 Thread Alex via Digitalmars-d-learn

On Friday, 4 January 2019 at 07:37:43 UTC, bauss wrote:

No, because you OVERRIDE A's foo().

A does not exist. A is B and when you cast B to A you just tell 
the compiler that the reference should only have A's signature 
available.


You're not assigning B to A.


Let's assume this is right. How to force a B object to behave 
like an A object? I thought casting is a possible approach...




Re: reimplementing an interface in a derived class

2019-01-04 Thread Alex via Digitalmars-d-learn

On Friday, 4 January 2019 at 02:13:27 UTC, Neia Neutuladh wrote:
I can't think of a single class system that works like that. 
C++, Java, C#, Dart, and TypeScript all work like D here. 
GObject in C works like D.


In the example below, the "2" of B.foo is printed only once. 
Independently of the cast type, after degrading a B to an A the 
degraded object behaves like an A.


´´´ C++ ´´´
#include 
class A
{
public:
int foo(){return 1;}
};
class B : public A
{
public:
int foo(){return 2;}
};

void performFoo(A *a)
{
std::cout << a->foo() << std::endl;
}

int main() {
auto a = new A();
auto b = new B();
std::cout << a->foo() << std::endl;
std::cout << b->foo() << std::endl;
std::cout << dynamic_cast(b)->foo() << std::endl;
std::cout << static_cast(b)->foo() << std::endl;
std::cout << reinterpret_cast(b)->foo() << std::endl;
performFoo(a);
performFoo(b);
return 0;
}
´´´
The point of OOP is that a bundle of data has particular ways 
of dealing with it. B has different data (at least 
theoretically), and that data has different ways of working 
with it. So if casting to a base class changed something to use 
the base class's behavior, you'd get bugs almost anywhere you 
used inheritance, since the derived class's data isn't being 
modified properly.


Now I have the feeling, I'm missing something elementary... sorry 
for this...
But take the classic example of OOP of an Animal and a Dog: 
Animal.

Let the animal implement some default move and eat behavior.
Let the dog override the move method and implement bark.
If you degrade the dog to the animal by casting it should still 
be able to move and eat, but not bark.


This should always be true for inherited objects as the base 
classes define enough content to manage proper behavior of their 
own. (Given they are not abstract, a function is not virtual and 
so on...)


Re: reimplementing an interface in a derived class

2019-01-03 Thread bauss via Digitalmars-d-learn

On Friday, 4 January 2019 at 00:19:05 UTC, Alex wrote:

On Friday, 4 January 2019 at 00:15:28 UTC, Neia Neutuladh wrote:

On Thu, 03 Jan 2019 23:44:15 +, Alex wrote:
I assume that is another bug and has nothing to do with 
interfaces...


B.foo is both overriding A.foo and implementing D.foo, so 
that's not a bug.


I don't have any interfaces in my example.
B.foo overrides A.foo. By casting a B object to be an A object, 
A's behavior should be granted, shouldn't it?


No, because you OVERRIDE A's foo().

A does not exist. A is B and when you cast B to A you just tell 
the compiler that the reference should only have A's signature 
available.


You're not assigning B to A.


Re: reimplementing an interface in a derived class

2019-01-03 Thread Neia Neutuladh via Digitalmars-d-learn
On Fri, 04 Jan 2019 00:19:05 +, Alex wrote:
> B.foo overrides A.foo. By casting a B object to be an A object, A's
> behavior should be granted, shouldn't it?

I can't think of a single class system that works like that. C++, Java, 
C#, Dart, and TypeScript all work like D here. GObject in C works like D.

The point of OOP is that a bundle of data has particular ways of dealing 
with it. B has different data (at least theoretically), and that data has 
different ways of working with it. So if casting to a base class changed 
something to use the base class's behavior, you'd get bugs almost anywhere 
you used inheritance, since the derived class's data isn't being modified 
properly.

The only situation in which you might possibly want that sort of behavior 
is if inheritance were only for ease of implementation, but then you'd 
want to disallow that sort of cast anyway. It would be like trying to cast 
an object to one of its fields.


Re: reimplementing an interface in a derived class

2019-01-03 Thread Neia Neutuladh via Digitalmars-d-learn
On Thu, 03 Jan 2019 23:44:15 +, Alex wrote:
> I assume that is another bug and has nothing to do with interfaces...

B.foo is both overriding A.foo and implementing D.foo, so that's not a bug.


Re: reimplementing an interface in a derived class

2019-01-03 Thread Alex via Digitalmars-d-learn

On Friday, 4 January 2019 at 00:15:28 UTC, Neia Neutuladh wrote:

On Thu, 03 Jan 2019 23:44:15 +, Alex wrote:
I assume that is another bug and has nothing to do with 
interfaces...


B.foo is both overriding A.foo and implementing D.foo, so 
that's not a bug.


I don't have any interfaces in my example.
B.foo overrides A.foo. By casting a B object to be an A object, 
A's behavior should be granted, shouldn't it?


Re: reimplementing an interface in a derived class

2019-01-03 Thread Alex via Digitalmars-d-learn

On Thursday, 3 January 2019 at 23:23:12 UTC, Neia Neutuladh wrote:

On Thu, 03 Jan 2019 22:30:48 +, kdevel wrote:

class A : D {
 int foo() { return 1; }
}

class B : A, D {
[...]

What is the meaning of the ", D"? It does not seem to make a 
difference if it is omitted.


B must provide its own implementation of D. It can't simply use 
A's implementation.


I assume that is another bug and has nothing to do with 
interfaces...


´´´
import std.traits;

alias parentOfB = BaseClassesTuple!B[0];

void main()
{
static assert(is(typeof(cast(parentOfB)(new B)) == parentOfB));
assert((cast(parentOfB)(new B)).foo == (new parentOfB).foo);
}

class A
{
int foo() { return 1; }
}

class B : A
{
override int foo() { return 2; }
}
´´´


Re: reimplementing an interface in a derived class

2019-01-03 Thread bauss via Digitalmars-d-learn

On Thursday, 3 January 2019 at 22:30:48 UTC, kdevel wrote:

https://dlang.org/spec/interface.html #11 has this code example:

```
interface D
{
int foo();
}

class A : D
{
int foo() { return 1; }
}

class B : A, D
{
override int foo() { return 2; }
}

...

B b = new B();
b.foo();// returns 2
D d = cast(D) b;
d.foo();// returns 2
A a = cast(A) b;
D d2 = cast(D) a;
d2.foo();   // returns 2, even though it is A's D, not 
B's D

```

What is the meaning of the ", D"? It does not seem to make a 
difference if it is omitted.


When you override foo() from A within B then you're omitting A's 
implementation.


That's because all functions are virtual by default and thus you 
override the implementation.


Basically you have something like (Simplified example)

A:
auto b = new B;
b.v_table["foo"] =  // If B doesn't override foo. 
(super = A)

b.v_table["foo"] =  // If B overrides foo.

When you call foo() it basically looks it up in the v_table.

Even if you cast B to A then the reference to A is still a 
reference to B but you just tell the compiler that the signature 
of your reference is A.


So when you do the following:

B b = new B();
b.foo();// returns 2
D d = cast(D) b;
d.foo();// returns 2
A a = cast(A) b;
D d2 = cast(D) a;
d2.foo();   // returns 2, even though it is A's D, not 
B's D


It really translates to this:
B b = new B();
b.foo();
D d = use_signature_of_D_on_a_reference_to_B(b);
d.foo(); // Still calling b.foo() because D is not really a type 
and still a reference to B.

A a = use_signature_of_A_on_a_reference_to_B(b);
a.foo(); // Still calling b.foo() because B implement's A's 
signature by having it as a super class. This means that right 
now A is technically B and you just stripped away the signature 
of B to the signature of A.

D d2 = use_signature_of_D_on_a_reference_to_A(a);
d2.foo(); // Calls B.foo() because as stated earlier A is really 
B.


There is no A actually ever existing in your scenario.

Only a reference to B that different signatures are cast from.


Re: reimplementing an interface in a derived class

2019-01-03 Thread Neia Neutuladh via Digitalmars-d-learn
On Thu, 03 Jan 2019 22:30:48 +, kdevel wrote:
> class A : D {
>  int foo() { return 1; }
> }
> 
> class B : A, D {
> [...]
>
> What is the meaning of the ", D"? It does not seem to make a difference
> if it is omitted.

B must provide its own implementation of D. It can't simply use A's 
implementation.