I thought this should work :-(

J

JAM

I thought this should work:

class A
{
protected void F();
}

class B : A
{
public List<A> items;

public void B()
{
items[0].F();
}
}

The idea was not to expose function F outside of class A but still
make it visible to B. But if A is just and item in some list that is
part of B, the compiler complains about access to F :-(
Do I have to expose F as public to be able to access it when
particular A is not a base for this particular B but when the A
belongs somehow to this particular B which has some different A as
base ?

JAM
 
A

Arne Vajhøj

I thought this should work:

class A
{
protected void F();
}

class B : A
{
public List<A> items;

public void B()
{
items[0].F();
}
}

The idea was not to expose function F outside of class A but still
make it visible to B. But if A is just and item in some list that is
part of B, the compiler complains about access to F :-(
Do I have to expose F as public to be able to access it when
particular A is not a base for this particular B but when the A
belongs somehow to this particular B which has some different A as
base ?

Two ideas:

1) Put the stuff in same assembly and use internal visibility.

2) If they can not be put in same assembly then still make
it internal and use the InternalsVisibleTo attribute to
make it work.

Not a pure solution, but maybe it is a practical solution for you.

Arne
 
P

Peter Duniho

JAM said:
I thought this should work:

class A
{
protected void F();
}

class B : A
{
public List<A> items;

public void B()
{
items[0].F();
}
}

The idea was not to expose function F outside of class A but still
make it visible to B. But if A is just and item in some list that is
part of B, the compiler complains about access to F :-(

That's correct. To access a protected member of a base class, your
class has to access that protected member via a variable of its own type.

Consider the alternative: if you could start accessing protected members
of _any_ instance of a class A just by inheriting A and doing it from
the sub-class, then accessibility protection would be basically
meaningless. You could bypass it anytime you want just by inheriting
the class you want to get at.

Note that if your "items" variable was a "List<B>", the access would
have been just fine. That's because the class B is trusted to access
protected members in instances of itself.

From the C# 3.0 specification:

When a protected instance member is accessed outside
the program text of the class in which it is declared,
and when a protected internal instance member is
accessed outside the program text of the program in
which it is declared, the access must take place within
a class declaration that derives from the class in which
it is declared. Furthermore, the access is required to
take place through an instance of that derived class type
or a class type constructed from it. This restriction
prevents one derived class from accessing protected members
of other derived classes, even when the members are
inherited from the same base class.
Do I have to expose F as public to be able to access it when
particular A is not a base for this particular B but when the A
belongs somehow to this particular B which has some different A as
base ?

That sentence is pretty awkward. I'm not sure it means what you meant
it to mean. But, if you're asking if you _have_ to use "public" to
write code in one type B that can access non-public members in a base
type A of that type B but without the compiler being able to verify that
the instance is in fact an instance of type B, strictly speaking the
answer is "no". An alternative to "public" that doesn't have the same
restriction as "protected" is "internal". But that only works if the
code is in the same assembly).

But as a general rule, yes…if you have a member in one class that you
want to be accessible via code not in an instance of the class in which
the member is defined, that member has to be public.

I would furthermore argue that if you find yourself trying to design a
class to the contrary of this, that you've made a mistake in the program
design. The accessibility rules are there for a reason, and even
"internal" should IMHO be used VERY sparingly. Any time you find
yourself trying to get around the given accessibility rules, it suggests
that you're leaking implementation details in a way that would negate
the benefit of abstracting your types in the first place.

Pete
 
J

JAM

That's correct.  To access a protected member of a base class, your
class has to access that protected member via a variable of its own type.

Consider the alternative: if you could start accessing protected members
of _any_ instance of a class A just by inheriting A and doing it from
the sub-class, then accessibility protection would be basically
meaningless.  You could bypass it anytime you want just by inheriting
the class you want to get at.

Sure, but I would do it on purpose so the assumption would be that I
know what I'm doing. I don't see the alternative as being so bad here.
Note that if your "items" variable was a "List<B>", the access would
have been just fine.  That's because the class B is trusted to access
protected members in instances of itself.

But that actually would make my program less self explanatory. In my
program class A is a node in the tree structure.
Class B is a root node of that tree. B requires slightly different
handling than A, that is why it is derived from A.
The list is a list of subnodes. It would make akward reading if the
list would be a list of rootnodes. Function F in my program simply
opens particular branch (recursively) from data file. However root
node cannot use F to open itself. It uses different function. But then
it opens it's entire branch using F for all it's subnodes from the
list. There is no reason for F to be used anywhere else. That is why I
tought it would be a good idea to hide it from public interface.
 From the C# 3.0 specification:

     When a protected instance member is accessed outside
     the program text of the class in which it is declared,
     and when a protected internal instance member is
     accessed outside the program text of the program in
     which it is declared, the access must take place within
     a class declaration that derives from the class in which
     it is declared. Furthermore, the access is required to
     take place through an instance of that derived class type
     or a class type constructed from it. This restriction
     prevents one derived class from accessing protected members
     of other derived classes, even when the members are
     inherited from the same base class.

Well. So it works as designed :-(
That sentence is pretty awkward.

Sorry. English is not my first language.
 I'm not sure it means what you meant
it to mean.  But, if you're asking if you _have_ to use "public" to
write code in one type B that can access non-public members in a base
type A of that type B but without the compiler being able to verify that
the instance is in fact an instance of type B, strictly speaking the
answer is "no".  An alternative to "public" that doesn't have the same
restriction as "protected" is "internal".  But that only works if the
code is in the same assembly).

Internal is fine for my program.
But as a general rule, yes…if you have a member in one class that you
want to be accessible via code not in an instance of the class in which
the member is defined, that member has to be public.

Well, then I think my particular case proves that C# in rare
situations is lacking more granular access control that would be
usefull.
I would furthermore argue that if you find yourself trying to design a
class to the contrary of this, that you've made a mistake in the program
design.

What you think about my example ? In my experinece with tree
structures it often happens that root node has slightly different
needs that other nodes.
 The accessibility rules are there for a reason, and even
"internal" should IMHO be used VERY sparingly.  Any time you find
yourself trying to get around the given accessibility rules, it suggests
that you're leaking implementation details in a way that would negate
the benefit of abstracting your types in the first place.
Pete- Hide quoted text -

- Show quoted text -

JAM
 
P

Peter Duniho

JAM said:
Sure, but I would do it on purpose so the assumption would be that I
know what I'm doing. I don't see the alternative as being so bad here.

OOP encapsulation rules are predicated on the assumption that any code
other than the code in the class is not written by someone who "knows
what they're doing".

If you would prefer to work without the constraints that these language
rules provide, you probably would prefer to work in a different
language. Alternatively, if you insist that you always "know what
you're doing", why not just make everything in the class public. Then
you have complete access, and don't have to worry about the compiler
looking over your shoulder every time you want to do something. :)

Not something I'd advise personally. But you can do it that way if you
find the rules too constraining.
But that actually would make my program less self explanatory.

Uh, not really. Not within the constraints of the C# language.
In my
program class A is a node in the tree structure.
Class B is a root node of that tree. B requires slightly different
handling than A, that is why it is derived from A.
The list is a list of subnodes. It would make akward reading if the
list would be a list of rootnodes.

If you can't guarantee that the elements in the list are of type B, then
IMHO your code has no business accessing protected members of the
instances in the list from code in class B.

If you _could_ guarantee the elements are of type B (sounds like you
can't, but speaking hypothetically), then of course using type B in the
list is more "self-explanatory".
Function F in my program simply
opens particular branch (recursively) from data file. However root
node cannot use F to open itself. It uses different function. But then
it opens it's entire branch using F for all it's subnodes from the
list. There is no reason for F to be used anywhere else. That is why I
tought it would be a good idea to hide it from public interface.

It's hard to speak of specifics without specific code. But having
written various tree-based UIs myself, including those linked to data
files and to file system structures, I can safely say that having your
tree made up of different kinds of nodes depending on their location
within the tree is a highly unusual, and highly suspect, design.

This is in fact consistent with my more general observation I mentioned
before: if you find yourself fighting the language, you've probably made
a design error somewhere.

This might be the design error you've made: having two different node
types in the same tree, at least as far as the tree itself is concerned
(of course, one can imagine a tree structure with varying node types,
but they would all inherit the same base class, and the code dealing
with the tree would only care about that base class, not all the various
sub-class types).
[...]
That sentence is pretty awkward.

Sorry. English is not my first language.

Well, then your sentence is surprisingly well constructed. :)
(Seriously, I never would have guessed English isn't your first
language, so you're doing way better than many native speakers of
English :) ).
[...]
But as a general rule, yes…if you have a member in one class that you
want to be accessible via code not in an instance of the class in which
the member is defined, that member has to be public.

Well, then I think my particular case proves that C# in rare
situations is lacking more granular access control that would be
usefull.

Personally, I think your particular case proves that you could improve
your design. :)
What you think about my example ? In my experinece with tree
structures it often happens that root node has slightly different
needs that other nodes.

I've written hundreds of tree structures in my career, and have never
had to have a root node be a different type or handled differently than
the other nodes.

I would be happy to try to offer more specific advice if you can provide
more details of your problem. But I do believe that you can solve your
problem quite well and elegantly without violating C#'s access rules,
and even without using "internal" as your access modifier.

Pete
 
J

JAM

OOP encapsulation rules are predicated on the assumption that any code
other than the code in the class is not written by someone who "knows
what they're doing".

Knows in a sense that since B is derieved from A my guess was that it
should see protected members of A even if A is not the base instance
of B. Obviously I was wrong, but I don't fully understand the reason
for this restriction. When I construct B derieved from A I expect B to
see protected members of it's base class. What makes it so different
if instance of A is not a base for particular B ? The author of class
A by making function "protected" already assumed that author of B will
eventually be allowed to use it and in order to use it must assume
responsibility for using it properly.
It's hard to speak of specifics without specific code.  But having
written various tree-based UIs myself, including those linked to data
files and to file system structures, I can safely say that having your
tree made up of different kinds of nodes depending on their location
within the tree is a highly unusual, and highly suspect, design.

I think you are too judgmental. This is not as "unusual" as you
suggest. Windows file system is a good example of such tree. The root
node is a disk drvie whereas nodes of the tree are directories. I do
realize that in fact behind "disk drive" is really root directory of
the drive, but still it makes easier to consider root node as
different from others. There is substantial amount of functionality
that applies to disk drive but is not applicable to some directory on
that drive. Windows 7 added Libraries, which probably need another
node type to distinguish them from conventional directory so one can
imagine even more rich tree. Windows Explorer also introduces node
callled "MyComputer" - the very top node of the entire tree which is
neither a disk drive nor directory and none of typical directory or
disk functions apply to it.
I would be happy to try to offer more specific advice if you can provide
more details of your problem.  But I do believe that you can solve your
problem quite well and elegantly without violating C#'s access rules,
and even without using "internal" as your access modifier.

My tree is similar to the one mentioned for Windows Explorer. It has
root node that has some of the functionality of subnodes but also has
much more additional functionality and stores additional information
It is always predefined to reside as the root. Every other node in the
tree is of the other class type and does not need extended
functionality or storage. It seemed usefull to make B root node and A
other nodes where B : A.
 
P

Peter Duniho

JAM said:
Knows in a sense that since B is derieved from A my guess was that it
should see protected members of A even if A is not the base instance
of B. Obviously I was wrong, but I don't fully understand the reason
for this restriction.

Okay…maybe I wasn't careful enough in my previous explanation. I'll try
again…
When I construct B derieved from A I expect B to
see protected members of it's base class.

I would like you to try to consider why class A has protected members in
the first place, rather than just private and public, and given that why
class B should have access to protected members in class A.

Here's _my_ answer to that: the protected members are there to support
inheritance that allows the derived class to manipulate or otherwise use
those members. You can't allow that access for private members, because
then you can't design classes that have implementation details that are
hidden even from derived classes. And obviously you don't want those
details to be public, because that's implementation, not interface.

So we have protected. But it's there to support inheritance. As such,
they should be visible only to the class that has inherited them. So,
code in class B does have access to protected members. But only in
instances of class B, because that's the only class that should have
access to _any_ hidden members of class B.

If that doesn't seem to help explain it, consider this: the usage of a
protected member is defined by the class in which its contained. Once
class B is permitted to inherit a protected member, it gets to impose
its own usage rules on the protected members.

But, class B does not have any specific knowledge regarding how any
other class might use that member.

For example:

class Temperature
{
public int Value
{
get { return _temp; }
set { _temp = value; }
}

protected int _temp;
}

class Fahrenheit : Temperature
{
public int Celsius { get { return (_temp - 32) * 5 / 9; } }
}

class Celsius : Temperature
{
public int Fahrenheit { get { return _temp * 9 / 5 + 32; } }
}

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?
What makes it so different
if instance of A is not a base for particular B ? The author of class
A by making function "protected" already assumed that author of B will
eventually be allowed to use it and in order to use it must assume
responsibility for using it properly.

But only in the context of the inheriting class.

Frankly, I think protected members should be generally avoided, and this
is ten times more true IMHO for variables. Even between base and
derived classes, hiding implementation is a very good thing.

But, inasmuch as there may be a need to share implementation between the
base class and the derived class, there's no way to ensure in the design
of the code that when one derived class accesses a protected member that
is actually a member of a completely different derived class, that it's
doing so in a way that is consistent with the first derived class's
understanding of the member.

Thus, that's simply not allowed.
I think you are too judgmental.

People who receive criticisms that they are unprepared to hear often
think that. Sorry about that. I do not intend to be judgmental, except
with respect to judging the _code_ and its design. Please don't take it
personally.
This is not as "unusual" as you suggest.

I have enough experience in the area for me to confidently say that it is.
Windows file system is a good example of such tree.

It's not, actually. Not in the sense that it supports the design you
seem to be working with.
The root
node is a disk drvie whereas nodes of the tree are directories.

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.

Why should a node representing a drive have access to otherwise-private
members in a node not representing a drive? Or vice a versa? If that
member is protected, it's because the derived class is expected to do
something special with it. Something special that is not shared in
common with every class that inherits the base class.

If the derived class is not doing anything special with the protected
member, then that means the member should not have been marked as
protected in the first place. It should have been private, with all of
the general-purpose implementation in the base class.

Or, looking at your example from a slightly different point of view: as
far as the _tree_ structure is concerned, the shared base class that
describes the tree is the only important thing. Any code related to the
management of the tree itself should not care whether the node
represents a drive or a directory within a drive. And inasmuch as any
code is specific to one type of node or the other, that code should
operate only on the type of node in which that code exists.
[...]
My tree is similar to the one mentioned for Windows Explorer. It has
root node that has some of the functionality of subnodes but also has
much more additional functionality and stores additional information
It is always predefined to reside as the root. Every other node in the
tree is of the other class type and does not need extended
functionality or storage. It seemed usefull to make B root node and A
other nodes where B : A.

Been there, done that, and having done that I know for sure you don't
need a design in which a protected member is accessible from without the
class actually inheriting that member.

Pete
 
J

JAM

JAM wrote:
...
If that doesn't seem to help explain it, consider this: the usage of a
protected member is defined by the class in which its contained.  Once
class B is permitted to inherit a protected member, it gets to impose
its own usage rules on the protected members.

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.
For example:

   class Temperature
   {
     public int Value
     {
       get { return _temp; }
       set { _temp = value; }
     }

     protected int _temp;
   }

   class Fahrenheit : Temperature
   {
     public int Celsius { get { return (_temp - 32) * 5 / 9; } }
   }

   class Celsius : Temperature
   {
     public int Fahrenheit { get { return _temp * 9 / 5 + 32; } }
   }

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 ? 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.

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. Maybe some other that public, protected or private
modifier would be needed to clarify this different approach.
But only in the context of the inheriting class.

Frankly, I think protected members should be generally avoided, and this
is ten times more true IMHO for variables.  Even between base and
derived classes, hiding implementation is a very good thing.

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
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. 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.
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. By forcing me to make function in A public in my specific
case, now I see the damn function every time I code something for A or
B and that was not my intent.
Been there, done that, and having done that I know for sure you don't
need a design in which a protected member is accessible from without the
class actually inheriting that member.

With all do respect I agree to disagree here.

JAM
 
F

Family Tree Mike

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...
 
P

Peter Duniho

JAM said:
[...]
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?
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
 
J

JAM

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 anerror
         }
     }

     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...

Excellent example Mike. Now I see the issue. I was missing this in
Peter's explanations. Thank you.

JAM
 
J

JAM


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 ?

JAM
 
P

Peter Duniho

JAM said:
[...]
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 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
 
J

JAM

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
 
P

Peter Duniho

JAM said:
[...]
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.

That was some thirty years ago. It's time to move on. I did, so I know
you can too. :)
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.

Afford what? Afford insisting that in spite of not being a professional
programmer, you know better than the professionals how a language should
be designed and used?

I mean no offense, but in this discussion you have repeatedly insisted
that your own point of view is the correct one, in spite of there being
a lot of evidence to the contrary, and refusing to accept that the
professionals might in fact have something useful to offer to you in the
way of insight into good programming practices.

In any case, a) if you really don't want empty fields in your data
structures, that's fine…you still don't need to access protected members
from outside the class where they exist, and b) as a person using .NET
you really need to get over the mentality of conserving data at all
costs, because the whole point of the managed programming environment is
to trade efficiency for productivity.

Pete
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top