Thread overview | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
February 22, 2014 hiding a class property behind a method | ||||
---|---|---|---|---|
| ||||
It seems to me that the following code should be illegal, but I am uncertain of it so I am posting here for a confirmation before I post it on bug tracker: http://dpaste.dzfl.pl/dae728734cc6 import std.stdio; class A { string x () { return "A"; }; } class B : A { override string x () { return "B"; }; } class C : A { string x = "C"; // should this be illegal? } void main () { A o1 = new B(); writeln(o1.x); // B A o2 = new C(); writeln(o2.x); // A } |
February 22, 2014 Re: hiding a class property behind a method | ||||
---|---|---|---|---|
| ||||
Posted in reply to luka8088 | On 02/22/2014 06:21 PM, luka8088 wrote:
> import std.stdio;
>
> class A {
> string x () { return "A"; };
> }
>
> class B : A {
> override string x () { return "B"; };
> }
>
> class C : A {
> string x = "C"; // should this be illegal?
> }
>
> void main () {
> A o1 = new B();
> writeln(o1.x); // B
>
> A o2 = new C();
> writeln(o2.x); // A
> }
Just an addition. The following line shows the problem:
writeln((cast(C)o2).x); // C
|
February 22, 2014 Re: hiding a class property behind a method | ||||
---|---|---|---|---|
| ||||
Posted in reply to luka8088 | On 02/22/2014 09:21 AM, luka8088 wrote:> It seems to me that the following code should be illegal, but I am > uncertain of it so I am posting here for a confirmation before I post it > on bug tracker: > > > http://dpaste.dzfl.pl/dae728734cc6 > > > import std.stdio; > > class A { > string x () { return "A"; }; > } > > class B : A { > override string x () { return "B"; }; > } > > class C : A { > string x = "C"; // should this be illegal? > } > > void main () { > A o1 = new B(); > writeln(o1.x); // B > > A o2 = new C(); > writeln(o2.x); // A > } > The code uses the two objects through the A interface and x() is a virtual function on that interface. When the C interface is used then we get C.x, which happens to be hiding the x() function of the base class. It looks normal to me. Ali |
February 22, 2014 Re: hiding a class property behind a method | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | On Saturday, 22 February 2014 at 17:41:58 UTC, Ali Çehreli wrote:
>
> The code uses the two objects through the A interface and x() is a virtual function on that interface.
>
> When the C interface is used then we get C.x, which happens to be hiding the x() function of the base class.
>
> It looks normal to me.
>
> Ali
Spec is silent on this, so this is indeed a question.
Actually A is not interface, so I don't understand why you mention it. And there is neither 'taking C interface' because static type is A, so A function is called, neither it hides function of the base class because it is base class function which is called. I don't understand you completely.
AFAIK this feature exists for many years, at least 3, possibly roots to D1. What happens is follows: since there is no function, base class virtual is not replaced, so virtual table of C looks like A, so A member function is called.
If example is modified, then
import std.stdio;
class A {
//string x () { return "A"; };
string x = "A";
}
class B : A {
//override string x () { return "B"; };
string x = "B";
}
class C : A {
//string x = "C"; // should this be illegal?
string x () { return "C"; }
}
void main () {
A o1 = new B();
A o2 = new C();
writeln(o1.x); // A
writeln(o2.x); //A
}
so it appears that data member have priority over function.
Probably this should be filed as a spec or compiler bug.
|
February 22, 2014 Re: hiding a class property behind a method | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | > The code uses the two objects through the A interface and x() is a virtual function on that interface. [...] > Ali The book "Programming in D" (r651) says in chapter "57.7 Using the subclass in place of the superclass", in the example about Clock and AlarmClock : void use(Clock clock) { ... } (sic) "In other words, although use() uses the object as a Clock, the actual object may be an inherited type that behaves in its own special way". Should'nt we understand that the first object is a B, the second object is a C and then should both behave like a B and a C, not like two A ? |
February 22, 2014 Re: hiding a class property behind a method | ||||
---|---|---|---|---|
| ||||
Posted in reply to Nynn007 | On 02/22/2014 12:06 PM, Nynn007 wrote: >> The code uses the two objects through the A interface and x() is a >> virtual function on that interface. > [...] >> Ali I agree. :) > > The book "Programming in D" (r651) says in chapter "57.7 Using the > subclass in place of the superclass", in the example about Clock and > AlarmClock : > > void use(Clock clock) { ... } > (sic) "In other words, although use() uses the object as a Clock, the > actual object may be an inherited type that behaves in its own special > way". I obviously agree with that as well. :) > > Should'nt we understand that the first object is a B, the second object > is a C and then should both behave like a B and a C, not like two A ? You are correct. What I meant above is that the code uses the two object as two As, which involves the "interface" of A. The behaviors may be different. Ali |
February 22, 2014 Re: hiding a class property behind a method | ||||
---|---|---|---|---|
| ||||
Posted in reply to Maxim Fomin | On 02/22/2014 10:00 AM, Maxim Fomin wrote: > On Saturday, 22 February 2014 at 17:41:58 UTC, Ali Çehreli wrote: >> >> The code uses the two objects through the A interface and x() is a >> virtual function on that interface. >> >> When the C interface is used then we get C.x, which happens to be >> hiding the x() function of the base class. Sorry. I meant "If the C interface is used", not "When the". >> >> It looks normal to me. >> >> Ali > > Spec is silent on this, so this is indeed a question. > > Actually A is not interface, so I don't understand why you mention it. I did not mean D's feature 'interface'. The code explicitly specifies the objects as As, comitting to A's class interface. (As in, every used defined type defines an interface.) > And there is neither 'taking C interface' because static type is A, so A > function is called, neither it hides function of the base class because > it is base class function which is called. I don't understand you > completely. I agree with all of that. > since there is no function, base class > virtual is not replaced, so virtual table of C looks like A, so A member > function is called. Exactly. Otherwise, when faced with such a situation the compiler would have to synthesize a virtual function for C's virtual table. string x() { return member_x; } > so it appears that data member have priority over function. It looks like name hiding, which I am familiar from C++. Name hiding does not differentiate between functions and variables. Ali |
February 22, 2014 Re: hiding a class property behind a method | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | On 02/22/2014 09:43 PM, Ali Çehreli wrote: > It looks like name hiding, which I am familiar from C++. Name hiding > does not differentiate between functions and variables. > > Ali > The problem is that hiding a name *is* a problem. When you are hiding a name, then a class would no longer behave as you would expect. It breaks LSP in a pretty awful way, and suddenly the *type* of a symbol changes based on what superclass you happened to use for a reference. class A { void f() {} } class B : A { int f; } A b = new B(); writeln(typeof(b.f).stringof); // void() B veryB = cast(B)b; writeln(typeof(veryB.f).stringof); // int Now suddenly, it's very important to use B as the type for a reference. This is very dangerous behavior in my opinion, and I think I've only used it *once* in C# - which requires you to be explicit about it - and I still feel dirty. Now what if a superclass implements a symbol that you are using in a subclass? I say we force it to be explicit as we finally did with `override`, which is shows some of the same issues, although not nearly as dangerous and hidden. I think member hiding is nearly always a bug, and we should be very explicit about it. |
February 22, 2014 Re: hiding a class property behind a method | ||||
---|---|---|---|---|
| ||||
Posted in reply to luka8088 | On Saturday, 22 February 2014 at 17:21:50 UTC, luka8088 wrote:
> It seems to me that the following code should be illegal, but I am
> uncertain of it so I am posting here for a confirmation before I post it
> on bug tracker:
[snip]
Nice find. I guess we could add this to the list of "ugly code caused by calling functions without parenthesis. If parenthesis were not optional, I don't think that the code would behave in such a horrible way, right?
|
February 22, 2014 Re: hiding a class property behind a method | ||||
---|---|---|---|---|
| ||||
Posted in reply to Francesco Cattoglio | On 02/22/2014 11:33 PM, Francesco Cattoglio wrote:
> On Saturday, 22 February 2014 at 17:21:50 UTC, luka8088 wrote:
>> It seems to me that the following code should be illegal, but I am
>> uncertain of it so I am posting here for a confirmation before I post it
>> on bug tracker:
> [snip]
>
> Nice find. I guess we could add this to the list of "ugly code caused by
> calling functions without parenthesis. If parenthesis were not optional,
> I don't think that the code would behave in such a horrible way, right?
The problem isn't about optional parenthesis or properties. It's the fact that
you can redefine a symbol to be something entierly different, and that this
difference will only be seen if you are looking at the symbol through the
"correct" type.
C# also allows has this feature, but you have to state explicitly that you are
hiding an existing symbol. D as a safe-by-default language should also require
this.
|
Copyright © 1999-2021 by the D Language Foundation