From: Peter Duniho on 2 Feb 2010 01:04 JAM wrote: > [...] >> But, class B does not have any specific knowledge regarding how any >> other class might use that member. > > This is what I don't fully get. I don't see the difference between > base instance and some other instance. If I can abuse protected member > of A when A is not base instance of B, then I can certainly make the > same abuse by incorrectly using protected member of A in B when A is a > base instance of B. Yes. But you can only affect instances of objects YOU wrote. It protects other programmers from your code stomping on their implementation details (and it also protects your own code from other programmers stomping on its implementation details). The basic idea being: if you want to screw up your own object, that's fine. But you aren't allowed to screw up other people's objects. >> [...] >> Now, ignoring for a moment that classes designed like that are probably >> not a good idea for other reasons, how is the Celsius class supposed to >> successfully use the variable _temp found in instances of Temperature >> that are not known to be also instances of Celsius? > > Well. Consider the opposite. If you have instance of Celsius, how > usage of base._temp makes it any different ? If author of Celsius has > no idea, of what exactly _temp does and how is used in Temperature, > why would author of B be any safer of using _temp in valid code case > when he is accessing it from the instance of B ? It's just an example. You make up your own example, where there's a protected field in a base class, and I could show you a similar problem in that one. But, yes�one of the _other_ problems the example I posted illustrates is just how dangerous it can be to even have a protected member in the first place, especially a data member. That doesn't negate the original point I was making. It just reinforces a completely different point. > Also consider, that > in my problem I was not attempting to use protected member of class A > but I was attempting to execute protected member of the instance of > class A from within class B. The only difference was, that that > instance of A was not a base instance of calling B. But the same basic issues apply. First, the "protected" modifier has to work the same no matter what it's applied to. So, even if a method was always safe, it would still have to follow the more conservative rules dictated by fields. But even a method is not always safe. For the same reason we have methods private to a class, we have methods that are private to a class and its descendants (i.e. "protected"). And for the same reason you don't want code outside your class calling its private methods (usually because the private methods manage object state outside of the public API, or because those methods don't do anything that would be useful outside the class), you don't want code outside your class calling its protected methods, whether those are inherited from a base class or not. The fact that the protected members are inherited from a base class does not make them any less private. They are still private members. They are just inheritable private members. > From the purity standpoint I can see your point that protected just > works this way as designed (which I did not know) and possibly has > some value. However my point is, that I see a value in my approach too > however rare. The very presumed rarity of your approach is strongly suggestive of its failure to provide proper OO encapsulation. In programming, the useful approaches show up over and over again, while the awkward, unmaintainable, bug-prone approaches tend to not. > [...] > I agree but there are times when it is the simplest approach. My > problem is, that I was forced to use public in A. In my opinion I > ended up with more polluted code. Now the damn function is visible to > every class and it was only needed to be visible in B Unless you are willing to share more details, I obviously cannot comment on the specifics. However, if only B ever needed the method, then why was it in A in the first place? Why not just let B implement it? >> Okay, let's take that abstraction as granted. We still cannot conclude >> that there's any good reason for a node of one type to access a >> protected member found in a node of another type. > > You proof is circular. I have no idea what you mean. The text you quoted before stating that my "proof is circular" isn't intended to be a proof at all. It's simply a summary of the following analysis. I certainly did not post any circular reasoning in justification of the design of "protected". > If there is no reason to access protected > member the member would be private. If the member if protected, there > must be a value in accessing it from class that inherits. And since > class that inherits can access it, it must do it correctly or the code > will produce garbage whether accessed class is a base instance or not. That is all correct. But note at no point in the above did you ever discuss classes other than the base class or the class that inherits the base class. None of the above in any way provides justification for the derived class to have access to the protected member in any _other_ class other than itself. > The whole discussion is about value of accessing protected member. At > least one value is that when I use code completion, protected > functions will not show up in the list so I can't use them by > laziness. Quite frankly, that is an awful, horrible reason to choose a particular accessibility. If you don't want a method to show up as a member of a class, then don't put it in the class. If you are concerned that you might use a public method that you shouldn't have, then for _sure_, you can't be trusted to safely use that protected method from outside the class that actually inherited it. Fortunately, the language simply won't let you do that at all. > With all do respect I agree to disagree here. Feel free. However, do note that this feature is not unique to C#. And it is not me with whom you are disagreeing, but the designers of C# and similar languages, all of whom are bright, thoughtful people. What are the odds that you alone on your island know so much more about proper design of an OOP language that they have all repeatedly made this mistake, a mistake that almost every other developer using those languages accepts and even agrees with, even in the face of your own arguments to the contrary? No doubt, you can't trust everything to a democracy. But when you're in a very tiny minority, and especially when your opinion contradicts a design that has been repeated over and over successfully, it's a really good time to start considering the possibility that you've made a mistake. Pete
From: JAM on 2 Feb 2010 07:18 On Feb 1, 10:29 pm, Family Tree Mike <FamilyTreeM...(a)ThisOldHouse.com> wrote: > JAM, > > So take the following classes: > > class A > { > protected void F() {} > } > > class B : A > { > public List<A> items; > > public void B() > { > items[0].F(); // <-- This does not generate an error > } > } > > class C > { > public List<A> items; > public void C() > { > items[0].F(); // <-- This generates an error > } > } > > You view the line in class B is acceptable only because the instance of > A (items [0]) is accessed from a subclass of A? But you also feel that > in class C, this would be illegal as C is not subclassing A, even though > it (items [0]) is still an instance of an A? > > I'd hate to think about diagnosing that code later, among other > nightmares... > > -- > Mike Excellent example Mike. Now I see the issue. I was missing this in Peter's explanations. Thank you. JAM
From: JAM on 2 Feb 2010 08:25 On Feb 2, 1:04 am, Peter Duniho <no.peted.s...(a)no.nwlink.spam.com> wrote: > ... Peter Mike's example was perfect to convince me. Now I see your point. > Unless you are willing to share more details, I obviously cannot comment > on the specifics. However, if only B ever needed the method, then why > was it in A in the first place? Why not just let B implement it? Here are details: A resides in every node of the tree except root. In the root node B:A resides. Method F() is used to store A and it's branch recursively to the disk. This was by far the easiest approach. Since recurssion is used I don't see how could I not that have F implemented in A. From the program standpoint I'm only interested in saving entire tree from B so the only consumer of F will be through calling B.Save() where Save() method of B will call F internally in recursive manner. That is why my intent was to hide F from public interface. > What are the odds that you alone on your island know so much more about > proper design of an OOP language that they have all repeatedly made this > mistake, a mistake that almost every other developer using those > languages accepts and even agrees with, even in the face of your own > arguments to the contrary? >... What is the point of polymorphism if you are not going to mix classes from the same hierarchy in the same data structure ? How do you implement tree structure for the file system ? The file node will not have subdirectories nor files so it does not need any list for subdirectories and it does not need list of files. But directory needs those constructs. So if I want to store files and directories in the same tree how can I do that without mixing classes ? > > Pete JAM
From: Peter Duniho on 2 Feb 2010 18:30 JAM wrote: >> [...] >> Unless you are willing to share more details, I obviously cannot comment >> on the specifics. However, if only B ever needed the method, then why >> was it in A in the first place? Why not just let B implement it? > > Here are details: > > A resides in every node of the tree except root. In the root node B:A > resides. > Method F() is used to store A and it's branch recursively to the disk. > This was by far the easiest approach. Since recurssion is used I don't > see how could I not that have F implemented in A. From the program > standpoint I'm only interested in saving entire tree from B so the > only consumer of F will be through calling B.Save() where Save() > method of B will call F internally in recursive manner. That is why my > intent was to hide F from public interface. That doesn't explain why the public Save() method is also not in A. Nor why you are trying to call F() on a _different_ object that the instance of B used to call Save(). Nor why the list of items is in B, not A (nor why that list is public for that matter). For an example of how normal code might work: class A { private List<A> children; protected void F() { // Save this instance's stuff foreach (A a in children) { a.F(); } } } class B : A { public void Save() { this.F(); } } Your statement that your method F() is recursive doesn't make any sense, given that in the code you posted the base class A has no representation of the tree structure. >> What are the odds that you alone on your island know so much more about >> proper design of an OOP language that they have all repeatedly made this >> mistake, a mistake that almost every other developer using those >> languages accepts and even agrees with, even in the face of your own >> arguments to the contrary? >> ... > > What is the point of polymorphism if you are not going to mix classes > from the same hierarchy in the same data structure ? Non sequitur. There's nothing about the act of traversing the tree that involves polymorphism, nor did anything in your code example show any polymorphic aspects. It may well be that your derived class B has some polymorphic feature in it, but you didn't include anything in your posts showing that, never mind explain how that relates to the specific question of traversing your tree structure. > How do you implement tree structure for the file system ? The file > node will not have subdirectories nor files so it does not need any > list for subdirectories and it does not need list of files. But > directory needs those constructs. So if I want to store files and > directories in the same tree how can I do that without mixing > classes ? You have lots of choices that don't involve the problem you've been asking about. Here's one possible option: class NodeBase { protected abstract IEnumerable<NodeBase> GetChildren(); protected void Save() { // do whatever, such as call an abstract "save this" method foreach (NodeBase node in GetChildren()) { node.Save(); } } } class FolderNode : NodeBase { private List<FolderNode> _folders; private List<FileNode> _files; protected override IEnumerable<NodeBase> GetChildren() { foreach (NodeBase node in _folders) { yield return node; } foreach (NodeBase node in _files) { yield return node; } } public void SaveFolder() { Save(); } } class FileNode : NodeBase { protected override IEnumerable<NodeBase> GetChildren() { yield break; } } If the above doesn't suit your tastes, pick something else. For that matter, just because you know a file node won't ever have children, that doesn't mean it's the end of the world for it to have a null or empty list of children. It's not like you worry about the TreeViewNode instances that are leaf nodes still carrying around empty lists of children, or your folder nodes having an empty list if they are themselves devoid of children. Pete
From: JAM on 3 Feb 2010 09:48 On Feb 2, 6:30 pm, Peter Duniho <no.peted.s...(a)no.nwlink.spam.com> wrote: > JAM wrote: > For an example of how normal code might work: > > class A > { > private List<A> children; > > protected void F() > { > // Save this instance's stuff > > foreach (A a in children) > { > a.F(); > } > } > } > > class B : A > { > public void Save() > { > this.F(); > } > } > > Your statement that your method F() is recursive doesn't make any sense, > given that in the code you posted the base class A has no representation > of the tree structure. When I asked the question I did not thoguht at the time that this was important to show, that A has a list of subnodes of A. You example almost would work in my case, except in my program root node stores differnt information on the disk. The information stored is not an extension of information stored by A but rater a different set on information. Therefore construct: public Save() { // Save B stuff here this.F(); } would not work, because it attempts to store (after B stuff) B as a regular A. Originally I was thinking about doing F() in A such: private F() { if (Parent == null) { // store B stuff here } else { // store A stuff here } } but that was not working because to store B F needed to know stuff that is unique to B. The next "obvious" solution was to write Save() function in B that looks like this: public void Save() { // Save B stuff here foreach (A a in children) A.F(); } but that was what got me into this private / protected / public issue. Regarding your file tree structure example I'm one of those amatour programmers raised in times when 5 kB of memory was considered to be quite a lot. Therefore I cringe when I see data structures that carry unused fileds. I tend to automatically think about stripping such fields from the data structure. I treat this as a challenge to have some fun. I don't program computers for living so I can afford this. > Pete- Hide quoted text - > > - Show quoted text - JAM
First
|
Prev
|
Next
|
Last
Pages: 1 2 3 4 Prev: Globalized propertyGrid description Next: Sort Error in Crystal Report Code with VS 2005 |