From: Peter Duniho on
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
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
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
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
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