www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - forbid field name conflict in class hierarchy

reply spir <denis.spir gmail.com> writes:
Hello,


I think the compiler should complain when sub-classes hold fields with the =
same name as super-classes. After all, names (in addition to types) are use=
d to identify. Intentionally reusing the same name would not only be bad de=
sign, but open the door to hidden bugs.
Remain unintentional name crash: eg forgot to remove a field when establish=
ed type hierarchy. Allowing same names lead to strange contradictions by th=
e language -- see below. Without such a rigor imposed the compiler, we can =
easily fall into traps such as:

class C {
    int i;
    this (int i) {
        this.i =3D i;
    }
}
class C1 : C {
    // forgot to remove i
    int i;
    int j;
    this (int i, int j) {
        super(i);	// think i is set?
        this.j =3D j;
    }
}
void main () {
    auto c1 =3D new C1(1,2);
    writeln(c1.i);  // 0
}

Got me 3 times already. I don't understand how it is even possible that C.i=
 is not the same as C1.i, but evidence is here... There is a contradiction:=
 i is set && not set. (explaination welcome ;-)

Denis
-- -- -- -- -- -- --
vit esse estrany =E2=98=A3

spir.wikidot.com
Nov 14 2010
next sibling parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
spir wrote:
 Hello,
 
 
 I think the compiler should complain when sub-classes hold fields with the
same name as super-classes. After all, names (in addition to types) are used to
identify. Intentionally reusing the same name would not only be bad design, but
open the door to hidden bugs.
 Remain unintentional name crash: eg forgot to remove a field when established
type hierarchy. Allowing same names lead to strange contradictions by the
language -- see below. Without such a rigor imposed the compiler, we can easily
fall into traps such as:
 
 class C {
     int i;
     this (int i) {
         this.i = i;
     }
 }
 class C1 : C {
     // forgot to remove i
     int i;
     int j;
     this (int i, int j) {
         super(i);	// think i is set?
         this.j = j;
     }
 }
 void main () {
     auto c1 = new C1(1,2);
     writeln(c1.i);  // 0
 }
 
 Got me 3 times already. I don't understand how it is even possible that C.i is
not the same as C1.i, but evidence is here... There is a contradiction: i is
set && not set. (explaination welcome ;-)
 
 Denis
 -- -- -- -- -- -- --
 vit esse estrany ☣
 
 spir.wikidot.com
 

This issue has been brought up several times before. I myself see no harm in this shadowing, though making a compiler issue a warning when shadowing *public* fields occurs would be a good thing. Shadowing non-public fields, in my opinion, is harmless, and preventing it would actually narrow down name choice with each subsequent subclassing. The other option that comes to mind is simply disallow public fields for classes. This may sound too strict, but I think that public fields is something that's not as usable for classes as for structs.
Nov 14 2010
next sibling parent reply Daniel Gibson <metalcaedes gmail.com> writes:
Stanislav Blinov schrieb:
 spir wrote:
 Hello,


 I think the compiler should complain when sub-classes hold fields with 
 the same name as super-classes. After all, names (in addition to 
 types) are used to identify. Intentionally reusing the same name would 
 not only be bad design, but open the door to hidden bugs.
 Remain unintentional name crash: eg forgot to remove a field when 
 established type hierarchy. Allowing same names lead to strange 
 contradictions by the language -- see below. Without such a rigor 
 imposed the compiler, we can easily fall into traps such as:

 class C {
     int i;
     this (int i) {
         this.i = i;
     }
 }
 class C1 : C {
     // forgot to remove i
     int i;
     int j;
     this (int i, int j) {
         super(i);    // think i is set?
         this.j = j;
     }
 }
 void main () {
     auto c1 = new C1(1,2);
     writeln(c1.i);  // 0
 }

 Got me 3 times already. I don't understand how it is even possible 
 that C.i is not the same as C1.i, but evidence is here... There is a 
 contradiction: i is set && not set. (explaination welcome ;-)

 Denis
 -- -- -- -- -- -- --
 vit esse estrany ☣

 spir.wikidot.com

This issue has been brought up several times before. I myself see no harm in this shadowing, though making a compiler issue a warning when shadowing *public* fields occurs would be a good thing. Shadowing non-public fields, in my opinion, is harmless, and preventing it would actually narrow down name choice with each subsequent subclassing.

No, only shadowing private fields is harmless (because the sub-class can't access them anyway), but shadowing protected fields is about as bad as shadowing public fields.
 The other option that comes to mind is simply disallow public fields for 
 classes. This may sound too strict, but I think that public fields is 
 something that's not as usable for classes as for structs.

Disallowing public fields is too restrictive IMHO.
Nov 14 2010
parent Stanislav Blinov <stanislav.blinov gmail.com> writes:
Daniel Gibson wrote:
 Stanislav Blinov schrieb:
 spir wrote:
 Hello,


 I think the compiler should complain when sub-classes hold fields 
 with the same name as super-classes. After all, names (in addition to 
 types) are used to identify. Intentionally reusing the same name 
 would not only be bad design, but open the door to hidden bugs.

This issue has been brought up several times before. I myself see no harm in this shadowing, though making a compiler issue a warning when shadowing *public* fields occurs would be a good thing. Shadowing non-public fields, in my opinion, is harmless, and preventing it would actually narrow down name choice with each subsequent subclassing.

No, only shadowing private fields is harmless (because the sub-class can't access them anyway), but shadowing protected fields is about as bad as shadowing public fields.

Well, yes. Even shadowing of private fields is as bad as long as a subclass is in the same module as base class. Come to think of it, maybe, it'd be better if the compiler warned about shadowing whenever shadowed name is directly visible, not just in case of public fields. Though the problem fully manifests itself in client code, where only public members are exposed.
 The other option that comes to mind is simply disallow public fields 
 for classes. This may sound too strict, but I think that public fields 
 is something that's not as usable for classes as for structs.

Disallowing public fields is too restrictive IMHO.

Maybe. I just always view public fields as encapsulation breakers. And silent invariant breakers. And maintenance cripplers :)
Nov 15 2010
prev sibling next sibling parent "Manfred_Nowak" <svv1999 hotmail.com> writes:
Stanislav Blinov wrote:

 The other option that comes to mind is

... support protocols for variables in non-release mode. -manfred
Nov 14 2010
prev sibling parent "Manfred_Nowak" <svv1999 hotmail.com> writes:
Jonathan M Davis wrote:

 Having public fields shadow each other is problematic.

Detecting a problem requires having a model. What does your model look like? -manfred
Nov 15 2010
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
spir:

 I think the compiler should complain when sub-classes hold fields with the
same name as super-classes.

I have a bug report on it: http://d.puremagic.com/issues/show_bug.cgi?id=5187 C# faces this problem with the "new" keyword that's denotes a field that the programmer wants to hide: public class Foo { public int x = 10; } public class Test : Foo { new public int x = 20; public static void Main() {} } Bye, bearophile
Nov 14 2010
parent bearophile <bearophileHUGS lycos.com> writes:
spir:

 What are use cases for this? (And wouldn't it be better practice to change
name even in supposed sensible cases?)

I don't know. C# shows a warning if an attribute is masked by another one. Then I think they have added that "new" syntax as a clean way to silence that warning. (I am not expert enough about C# to know the logic behind most of it design decisions. Such explanations are often not present even inside books about a programming language. TDPL has some of such explanations). Bye, bearophile
Nov 14 2010
prev sibling next sibling parent spir <denis.spir gmail.com> writes:
On Sun, 14 Nov 2010 22:09:59 +0300
Stanislav Blinov <stanislav.blinov gmail.com> wrote:

 spir wrote:
 Hello,
=20
=20
 I think the compiler should complain when sub-classes hold fields with =


used to identify. Intentionally reusing the same name would not only be ba= d design, but open the door to hidden bugs.
 Remain unintentional name crash: eg forgot to remove a field when estab=


y the language -- see below. Without such a rigor imposed the compiler, we = can easily fall into traps such as:
=20
 class C {
     int i;
     this (int i) {
         this.i =3D i;
     }
 }
 class C1 : C {
     // forgot to remove i
     int i;
     int j;
     this (int i, int j) {
         super(i);	// think i is set?
         this.j =3D j;
     }
 }
 void main () {
     auto c1 =3D new C1(1,2);
     writeln(c1.i);  // 0
 }
=20
 Got me 3 times already. I don't understand how it is even possible that=


ion: i is set && not set. (explaination welcome ;-)
=20
 Denis
 -- -- -- -- -- -- --
 vit esse estrany =E2=98=A3
=20
 spir.wikidot.com
=20

This issue has been brought up several times before. I myself see no=20 harm in this shadowing, though making a compiler issue a warning when shadowing *public* fields occurs would be a good thing. Shadowing non-public fields, in my opinion, is harmless, and preventing=20 it would actually narrow down name choice with each subsequent subclassin=

I don't understand in which case you need to reuse the same name in a subcl= ass for a _different_ field -- whether the field is public or private does = not seem really relevant to me. But maybe I overlook some common use case.
 The other option that comes to mind is simply disallow public fields for=

 classes. This may sound too strict, but I think that public fields is=20
 something that's not as usable for classes as for structs.

Here, I guess you're touching programming style. I personly am allergic to = accessors for everything. Denis -- -- -- -- -- -- -- vit esse estrany =E2=98=A3 spir.wikidot.com
Nov 14 2010
prev sibling next sibling parent spir <denis.spir gmail.com> writes:
On Sun, 14 Nov 2010 14:22:56 -0500
bearophile <bearophileHUGS lycos.com> wrote:

 spir:
=20
 I think the compiler should complain when sub-classes hold fields with =


=20
 I have a bug report on it:
 http://d.puremagic.com/issues/show_bug.cgi?id=3D5187

You have bug reports for everything and the rest ;-)
 C# faces this problem with the "new" keyword that's denotes a field that =

=20
 public class Foo {
     public int x =3D 10;
 }
 public class Test : Foo {
     new public int x =3D 20;
     public static void Main() {}
 }

What are use cases for this? (And wouldn't it be better practice to change = name even in supposed sensible cases?) denis -- -- -- -- -- -- -- vit esse estrany =E2=98=A3 spir.wikidot.com
Nov 14 2010
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday 14 November 2010 11:29:55 spir wrote:
 On Sun, 14 Nov 2010 22:09:59 +0300
 Stanislav Blinov <stanislav.blinov gmail.com> wrote:
 This issue has been brought up several times before. I myself see no
 harm in this shadowing, though making a compiler issue a warning
 when shadowing *public* fields occurs would be a good thing.
 Shadowing non-public fields, in my opinion, is harmless, and preventing
 it would actually narrow down name choice with each subsequent
 subclassing.

I don't understand in which case you need to reuse the same name in a subclass for a _different_ field -- whether the field is public or private does not seem really relevant to me. But maybe I overlook some common use case.

Private fields are effectively hidden from derived classes. Derived classes shouldn't care what they're named and shouldn't have to care. The only time that it becomes any kind of issue is if both the base class and derived class are in the same module, since then the derived class has access to the base class' private members and functions (even though it probably shouldn't actually use them) from being in the same module. Having public fields shadow each other is problematic. Having private fields do so should be irrelevant. - Jonathan M Davis
Nov 14 2010
prev sibling next sibling parent spir <denis.spir gmail.com> writes:
On Sun, 14 Nov 2010 16:25:56 -0800
Jonathan M Davis <jmdavisProg gmx.com> wrote:

 On Sunday 14 November 2010 11:29:55 spir wrote:
 I don't understand in which case you need to reuse the same name in a
 subclass for a _different_ field -- whether the field is public or priv=


 does not seem really relevant to me. But maybe I overlook some common u=


 case.

Private fields are effectively hidden from derived classes. Derived class=

 shouldn't care what they're named and shouldn't have to care. The only ti=

 it becomes any kind of issue is if both the base class and derived class =

 the same module, since then the derived class has access to the base clas=

 private members and functions (even though it probably shouldn't actually=

 them) from being in the same module.
=20
 Having public fields shadow each other is problematic. Having private fie=

 should be irrelevant.
=20
 - Jonathan M Davis

Right, this makes sense. Denis -- -- -- -- -- -- -- vit esse estrany =E2=98=A3 spir.wikidot.com
Nov 15 2010
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday 15 November 2010 02:29:55 Stanislav Blinov wrote:
 Daniel Gibson wrote:
 Disallowing public fields is too restrictive IMHO.

Maybe. I just always view public fields as encapsulation breakers. And silent invariant breakers. And maintenance cripplers :)

Personally, it's the kind of thing that I generally avoid, but there are situations where it makes good sense to have them. I think that it's one of those cases where the programmer should have the freedom to choose. Most of the time that choice should probably be property functions over public member variables, but forcing the issue is definitely too restrictive. - Jonathan M Davis
Nov 15 2010
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, November 15, 2010 06:00:33 Manfred_Nowak wrote:
 Jonathan M Davis wrote:
 Having public fields shadow each other is problematic.

Detecting a problem requires having a model. What does your model look like?

You're going to have to be more specific in your question than that. It's not at all clear what you're asking. Public and protected functions use polymorphism. Public and protected member variables do not. So, it becomes error prone to have public or protected member variables which shadow each other. It becomes easy to end up in a situation where you're not using the one that you think that you're using - especially when code gets changed. - Jonathan M Davis
Nov 15 2010
prev sibling next sibling parent spir <denis.spir gmail.com> writes:
On Mon, 15 Nov 2010 09:45:26 -0800
Jonathan M Davis <jmdavisProg gmx.com> wrote:

 On Monday, November 15, 2010 06:00:33 Manfred_Nowak wrote:
 Jonathan M Davis wrote:
 Having public fields shadow each other is problematic.

Detecting a problem requires having a model. What does your model look like?

You're going to have to be more specific in your question than that. It's=

 all clear what you're asking.
=20
 Public and protected functions use polymorphism. Public and protected mem=

 variables do not. So, it becomes error prone to have public or protected =

 variables which shadow each other. It becomes easy to end up in a situati=

 where you're not using the one that you think that you're using - especia=

 when code gets changed.

True. There is an issue in the static model of OO, with class hierarchy: me= thods are dispatched, data fields are not. If there are "same" fields (same= name & type), then the one of the superclass is used. The only safe altern= ative would be to have runtime dispatch of fields like of methods, but this= is indeed costly. (This "staticity" also leads to the side-effect that one cannot write gener= ic routines which variables (from parameters or result of calls) have the s= uperclass as declared type but also use subclass fields. To be able to do i= t, I end up adding subclass fields to the superclass. I know it's wrong, bu= t haven't found the right way to do it. I don't feel like "downcasting" mos= t variables in most routines.) Denis -- -- -- -- -- -- -- vit esse estrany =E2=98=A3 spir.wikidot.com
Nov 15 2010
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday 15 November 2010 11:44:11 spir wrote:
 On Mon, 15 Nov 2010 09:45:26 -0800
 
 Jonathan M Davis <jmdavisProg gmx.com> wrote:
 On Monday, November 15, 2010 06:00:33 Manfred_Nowak wrote:
 Jonathan M Davis wrote:
 Having public fields shadow each other is problematic.

Detecting a problem requires having a model. What does your model look like?

You're going to have to be more specific in your question than that. It's not at all clear what you're asking. Public and protected functions use polymorphism. Public and protected member variables do not. So, it becomes error prone to have public or protected member variables which shadow each other. It becomes easy to end up in a situation where you're not using the one that you think that you're using - especially when code gets changed.

True. There is an issue in the static model of OO, with class hierarchy: methods are dispatched, data fields are not. If there are "same" fields (same name & type), then the one of the superclass is used. The only safe alternative would be to have runtime dispatch of fields like of methods, but this is indeed costly. (This "staticity" also leads to the side-effect that one cannot write generic routines which variables (from parameters or result of calls) have the superclass as declared type but also use subclass fields. To be able to do it, I end up adding subclass fields to the superclass. I know it's wrong, but haven't found the right way to do it. I don't feel like "downcasting" most variables in most routines.)

I'm not sure that pure OO would even allow for public variables. I do really have to wonder what you're doing though that you feel the need to access subclass fields using super class references. That just screams that it shouldn't be a public member variable (and truth be told, public member variables are generally considered bad practice except in simple objects - which would generally be structs in D). And if you really need the subclass type, then you should be using the subclass type, not the super class type. Also, return types are covariant, so you can return a subclass from overridden functions instead of the super class like the function which was overridden does. Maybe that would help. It would depend on what exactly you're doing though. - Jonathan M Davis
Nov 15 2010
prev sibling next sibling parent reply spir <denis.spir gmail.com> writes:
On Mon, 15 Nov 2010 12:32:07 -0800
Jonathan M Davis <jmdavisProg gmx.com> wrote:

 On Monday 15 November 2010 11:44:11 spir wrote:
 On Mon, 15 Nov 2010 09:45:26 -0800
=20
 Jonathan M Davis <jmdavisProg gmx.com> wrote:
 On Monday, November 15, 2010 06:00:33 Manfred_Nowak wrote:
 Jonathan M Davis wrote:
 Having public fields shadow each other is problematic.

Detecting a problem requires having a model. What does your model look like?

You're going to have to be more specific in your question than that. =



 not at all clear what you're asking.
=20
 Public and protected functions use polymorphism. Public and protected
 member variables do not. So, it becomes error prone to have public or
 protected member variables which shadow each other. It becomes easy to
 end up in a situation where you're not using the one that you think t=



 you're using - especially when code gets changed.

True. There is an issue in the static model of OO, with class hierarchy: methods are dispatched, data fields are not. If there are "same" fields (same name & type), then the one of the superclass is used. The only sa=


 alternative would be to have runtime dispatch of fields like of methods,
 but this is indeed costly.
=20
 (This "staticity" also leads to the side-effect that one cannot write
 generic routines which variables (from parameters or result of calls) h=


 the superclass as declared type but also use subclass fields. To be able
 to do it, I end up adding subclass fields to the superclass. I know it's
 wrong, but haven't found the right way to do it. I don't feel like
 "downcasting" most variables in most routines.)

I'm not sure that pure OO would even allow for public variables. [...] That just screams that it shouldn't=20 be a public member variable (and truth be told, public member variables a=

 generally considered bad practice except in simple objects - which would=

 generally be structs in D).

en writing methods of the class hierarchy.
 I do really=20
 have to wonder what you're doing though that you feel the need to access=

 subclass fields using super class references. [...] And if you really nee=

 should be using the subclass type, not the super class type

For instance a nested/recursive structure analog to a tree. There may be le= af nodes (only element), branch nodes (only subnodes), both, special ones w= ith different kinds of values, etc... Custom routines may need to use other methods to explore a branch's childre= n, get its leaves, filter, or whatever. All these tool methods are generic = (meaning must use the top Node type), but the custom routines need to acces= s subtype-specific fields. Thus, "down-casting" all the time. I find it tiresome (and bug-prone, because sometimes the absence of a field= s seems not caught, for any reason), so I add fields to the top type.
 Also, return types=20
 are covariant, so you can return a subclass from overridden functions ins=

 the super class like the function which was overridden does. Maybe that w=

 help. It would depend on what exactly you're doing though.

Yes, but doesn't this mean I should override all tool methods for all subty= pes, just so that I don't need to down-cast their results (in the routines = that use them)? I think a better solution would be that the compiler does not prevent us to= use subtype fields. Why does it do so? In the worst case, if the field doe= s not exist, we'll get an error, anyway.
 - Jonathan M Davis

Denis -- -- -- -- -- -- -- vit esse estrany =E2=98=A3 spir.wikidot.com
Nov 15 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
spir:

 (and bug-prone, because sometimes the absence of a fields seems not caught,
for any reason), so I add fields to the top type.

What do you mean? Do you have an example? (Adding fields to the top type doesn't look like a good idea, generally). Bye, bearophile
Nov 16 2010
parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 16.11.2010 14:40, spir wrote:
 On Tue, 16 Nov 2010 05:37:52 -0500
 bearophile<bearophileHUGS lycos.com>  wrote:

 spir:

 (and bug-prone, because sometimes the absence of a fields seems not caught,
for any reason), so I add fields to the top type.

(Adding fields to the top type doesn't look like a good idea, generally). Bye, bearophile

Each time I need to post-process results, since I apparently get Nodes (even if I know they are actually of one or the other type), I would first have to down-cast each node to the proper kind before doing anything. Else, I would get compiler errors, or plain bugs, for not having the proper field. So, I ended up setting fake fields on Node (and remove them from the sub-classes). And yes, I agree it's A Bad Thing to do. Just tell me of an elegant solution, and I apply it at once.

That's what opApply is made for. Namely: internal iteration. Idea - basically what you need is apply some block of code (delegate) on each element. If you provide in your node-like classes function opApply with signature: int opApply(int delegate(ref A)); //where A is your data-type foreach(a; node){ writeln(a);//here a is element of data not Node or some such } Is rewritten as node.opApply((ref a){ writeln(a); return 0;}); compiler rewrites code with breaks and so on to return 1, while at the normal end of flow to return 0 To get that idea better, try this example program import std.stdio; class Node{ abstract int opApply(int delegate(ref int)); } class Leaf: Node{ this(int _data){ data = _data; } int data; int opApply(int delegate(ref int) dg){ return dg(data); } } class Branch: Node{ Node[] nodes; this(Node[] _nodes...){ nodes = _nodes.dup; } int opApply(int delegate (ref int) dg){ Node[] n = nodes; while(n.length){ int result = n[0].opApply(dg); if(result) return result; ///to handle breaks n = n[1..$]; } return 0; } } void main(){ Branch b = new Branch(new Leaf(17), new Leaf(19)); Node n = new Branch(new Leaf(10),new Leaf(20),b); foreach(val;n){ if(val == 17)//try playing around with break break; writeln(val); } } Also check the section 12.10 in TDPL if you have one, it goes in great detail about it.
 Denis
 -- -- -- -- -- -- --
 vit esse estrany ☣

 spir.wikidot.com

-- Dmitry Olshansky
Nov 16 2010
prev sibling next sibling parent spir <denis.spir gmail.com> writes:
On Tue, 16 Nov 2010 05:37:52 -0500
bearophile <bearophileHUGS lycos.com> wrote:

 spir:
=20
 (and bug-prone, because sometimes the absence of a fields seems not cau=


=20
 What do you mean? Do you have an example?
 (Adding fields to the top type doesn't look like a good idea, generally).
=20
 Bye,
 bearophile

For instance, I have 2 sub-classes of nodes: one leaf kind with element (he= re called slice), one branch kind with an array of (child) nodes. They are = exclusive, and none of the data fields should appear on the top Node type. = But everywhere the Node class must be used, since a branch (as the top tree= ) can indifferently hold leaves or sub-branches, right? Each time I need to post-process results, since I apparently get Nodes (eve= n if I know they are actually of one or the other type), I would first have= to down-cast each node to the proper kind before doing anything. Else, I w= ould get compiler errors, or plain bugs, for not having the proper field. S= o, I ended up setting fake fields on Node (and remove them from the sub-cla= sses). And yes, I agree it's A Bad Thing to do. Just tell me of an elegant = solution, and I apply it at once. Denis -- -- -- -- -- -- -- vit esse estrany =E2=98=A3 spir.wikidot.com
Nov 16 2010
prev sibling next sibling parent spir <denis.spir gmail.com> writes:
On Tue, 16 Nov 2010 05:37:52 -0500
bearophile <bearophileHUGS lycos.com> wrote:

 spir:
=20
 (and bug-prone, because sometimes the absence of a fields seems not cau=


=20
 What do you mean? Do you have an example?
 (Adding fields to the top type doesn't look like a good idea, generally).
=20
 Bye,
 bearophile

PS: And I guess clients of the lib face the same issues. denis -- -- -- -- -- -- -- vit esse estrany =E2=98=A3 spir.wikidot.com
Nov 16 2010
prev sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Tuesday, November 16, 2010 03:40:24 spir wrote:
 On Tue, 16 Nov 2010 05:37:52 -0500
 
 bearophile <bearophileHUGS lycos.com> wrote:
 spir:
 (and bug-prone, because sometimes the absence of a fields seems not
 caught, for any reason), so I add fields to the top type.

What do you mean? Do you have an example? (Adding fields to the top type doesn't look like a good idea, generally). Bye, bearophile

For instance, I have 2 sub-classes of nodes: one leaf kind with element (here called slice), one branch kind with an array of (child) nodes. They are exclusive, and none of the data fields should appear on the top Node type. But everywhere the Node class must be used, since a branch (as the top tree) can indifferently hold leaves or sub-branches, right? Each time I need to post-process results, since I apparently get Nodes (even if I know they are actually of one or the other type), I would first have to down-cast each node to the proper kind before doing anything. Else, I would get compiler errors, or plain bugs, for not having the proper field. So, I ended up setting fake fields on Node (and remove them from the sub-classes). And yes, I agree it's A Bad Thing to do. Just tell me of an elegant solution, and I apply it at once.

Well, I think that I'd have to study your code to get quite what you're doing. However, I would consider _any_ case in code where you specifically cast to a derived class from a base class to be a code smell. My general reaction is that there _has_ to be a better, cleaner way to do it, and that it stinks of bad design. However, I'd have to really understand what you're doing to give a better suggestion, and just because it's _almost_ always a bad idea doesn't mean that it's _always_ a bad idea. - Jonathan M Davis
Nov 16 2010