For future reference: nested classes and access modifiers (protected, protected internal)

R

raylopez99

The below source code is just for future reference, since I had
problems understanding the use of access modifiers "protected" and
"protected internal" with the examples on the net. Nothing beats
doing a demonstration program yourself however.

Actually the below example doesn't show how using "protected internal"
will allow you access of a member from outside the namespace the
member class is found in, but you get the picture.

Sorry for any line breaks, but I copied and pasted from Word.

Program shows: how even private members of a enclosing class can be
accessed by the nested class enclosed by the enclosing class; how
protected/ protected internal works; how you can instantiate either
the nested class, the enclosing class, or both; how instantiation by
"new" overrides and/or is required by a nested class, to access the
enclosing class.

Frankly I think the access modifiers in C# are more confusing and can
lead to spagetti code quicker than C++, but that's another matter.

RL

using System;
using System.Collections.Generic;
using System.Text;

namespace nestc001
{

/// <summary>
/// Summary Using Nested classes with access modifier "protected
internal"
/// </summary>
///
class NestedOuterClass1
{
private int magic_no;
public int magic_noPublic;
public int[] arr_outerCl;
public NestedInterClass0 mySeemingViolationInnerClass;
public NestedInnerClassTWO
my2ndInnerClassThatCanAccessPrivateMembersOfOuterClass;


public NestedOuterClass1()
{
magic_no = 1111111;
magic_noPublic = 999;
arr_outerCl = new int[3] { 111, 222, 333 };
mySeemingViolationInnerClass = new
NestedInterClass0(69); //works, despite being protected, since
'protected AND internal' (more expansive)
my2ndInnerClassThatCanAccessPrivateMembersOfOuterClass =
new NestedInnerClassTWO();

} //end of constructor for outer class

protected int[] Function01NestedOuterClass1(NestedInterClass0
O)
{
arr_outerCl = new int[3];
arr_outerCl = O.arr_innerCl;
return arr_outerCl;
}

public int[] Function02NestedOuterClass2(NestedInterClass0 O)
{

arr_outerCl = O.arr_innerCl;
return arr_outerCl;
}


public int[] interfaceFunction01NestedOuterClass1()
{
NestedInterClass0 Internal_ICl = new NestedInterClass0();
// BTW: Internal_ICl.// cannot see any outer class member
here, since 'temp' and 'local', but other inner class
mySeemingViolationInnerClass can!
arr_outerCl = Function01NestedOuterClass1(Internal_ICl);
return arr_outerCl;
}

public int[] return_the_arr_outerCl_noMatterWhatItIs()
{
return arr_outerCl;

}

public void Access_even_internal_members()
{
// mySeemingViolationInnerClass.//nothing from outer class
or second inner class accessible here
//
my2ndInnerClassThatCanAccessPrivateMembersOfOuterClass.jay = 0;
}

// protected class NestedInterClass0 doesn't give sufficent
privileged to any class other than the enclosed class (outer class) to
run any function, even if labeled 'public', so changed to 'protected
internal'

protected internal class NestedInterClass0
{
public int j;
public int[] arr_innerCl;
public NestedInterClass0()
{
arr_innerCl = new int[3] { 10, 20, 30 };
j = 1001;

}
public NestedInterClass0(int i)
{
j = i;
arr_innerCl = new int[3] { 55, 66, 77 };
}

public int NestInnerC0Function()
{
return 1;
}
public int[] change_the_arr_innerCl()
{
for (int i = 0; i < 3; i++)
{
arr_innerCl = i * i; //0,1,4

}
return arr_innerCl;
}
}

public class NestedInnerClassTWO
//second nested inner class, this time access modifier is public, so
this class can access enclosing outer class private numbers
{
public int jay;
public NestedInnerClassTWO()
{
jay = 1;
// jay = NestedOuterClass1.//nothing! cannot access
any members of outerclass
}

public int MyNICTWOfunction ()
{
NestedOuterClass1 myNOC1 = new NestedOuterClass1(); //
instantiation req'd!
// myNOC1.magic_no = 100000; //can override private
number if you want...
return myNOC1.magic_no; // no overriding, should get
magic_no = 1111111;

}
public int MyNICTWOfunction2()
{
NestedOuterClass1 myNOC1 = new NestedOuterClass1(); //
instantiation req'd
return myNOC1.magic_noPublic;

}
}
}

public static class Tester
{
public static void MMain()
{
int[] TestArr = new int[3];

NestedOuterClass1 myNestedOuterClass1 = new
NestedOuterClass1();

NestedOuterClass1.NestedInterClass0 myNIC0 = new
NestedOuterClass1.NestedInterClass0();
Console.WriteLine("myNIC0 reached, since 'protected
internal',NestedInterClass0, with magic #:{1}, magic# public: {2}!",
myNIC0.NestInnerC0Function(),
myNestedOuterClass1.my2ndInnerClassThatCanAccessPrivateMembersOfOuterClass.MyNICTWOfunction(),
myNestedOuterClass1.my2ndInnerClassThatCanAccessPrivateMembersOfOuterClass.MyNICTWOfunction2());

TestArr = myNestedOuterClass1.arr_outerCl;
int ll01 = TestArr.Length;

for (int i = 0; i < ll01; i++)
{
Console.WriteLine("TestArr[{0}] is: {1}", i,
TestArr);

}

TestArr =
myNestedOuterClass1.interfaceFunction01NestedOuterClass1();

for (int i = 0; i < ll01; i++)
{
Console.WriteLine("TestArr(2)[{0}] is: {1}", i,
TestArr);

}

myNIC0.change_the_arr_innerCl();

myNestedOuterClass1.Function02NestedOuterClass2(myNIC0);
TestArr =
myNestedOuterClass1.return_the_arr_outerCl_noMatterWhatItIs();


for (int i = 0; i < ll01; i++)
{
Console.WriteLine("TestArr(3)[{0}] is: {1}", i,
TestArr);

}

}
}
}



/*
/////////// output, after running class Tester from inside of main():

myNIC0 reached, since 'protected internal',NestedInterClass0, with
magic #:11111
11, magic# public: 999!
TestArr[0] is: 111
TestArr[1] is: 222
TestArr[2] is: 333
TestArr(2)[0] is: 10
TestArr(2)[1] is: 20
TestArr(2)[2] is: 30
TestArr(3)[0] is: 0
TestArr(3)[1] is: 1
TestArr(3)[2] is: 4
Press any key to continue . . .
*/
 
J

Jon Skeet [C# MVP]

Program shows: how even private members of a enclosing class can be
accessed by the nested class enclosed by the enclosing class; how
protected/ protected internal works; how you can instantiate either
the nested class, the enclosing class, or both; how instantiation by
"new" overrides and/or is required by a nested class, to access the
enclosing class.

Could you explain what you mean by the last point? I don't understand
what you mean, but I *suspect* you've misunderstood something.

Jon
 
R

raylopez99

Could you explain what you mean by the last point? I don't understand
what you mean, but I *suspect* you've misunderstood something.


Thanks Jon. I'd be happy to, since I'm learning:

This part:

*/

public int MyNICTWOfunction ()
{
NestedOuterClass1 myNOC1 = new NestedOuterClass1(); //
instantiation req'd!
// myNOC1.magic_no = 100000; //can override private
number if you want...
return myNOC1.magic_no; // no overriding, should get
magic_no = 1111111;
}

/*

Without the "new NestedOuterClass1()" you cannot have
"myNOC1.magic_no = 100000;" in the next line.

RL
 
P

Peter Duniho

raylopez99 said:
[...]
how instantiation by
"new" overrides and/or is required by a nested class, to access the
enclosing class.

As Jon wrote, you may have misunderstood something.

Instantiation of _any_ class is required in order to access instance
members, regardless of where that class is declared. So this is not
particular to the question of nested classes.

I think the important thing here, and perhaps what may be the confusing
aspect, is that having a class declared within another class does not
create a new instance of that contained class automatically when you
have an instance of the containing class.

Or put another way: anything that would simply be a declaration, like
code to declare a class, a struct, an interface, a delegate type, etc.
is always just a declaration of that thing, even when found inside the
declaration of some other thing. It affects the visibility and scope of
the thing you are declaring, but the thing is not itself automatically
instantiated, just as the same kind of thing is not automatically
instantiated when declared at the outermost level of the namespace.

I'm also not clear on why you believe access modifiers would result in
spaghetti code, but that's not related to the above (I think :) ).

Pete
 
R

raylopez99

Instantiation of _any_ class is required in order to access instance
members, regardless of where that class is declared. So this is not
particular to the question of nested classes.
I think the important thing here, and perhaps what may be the confusing
aspect, is that having a class declared within another class does not
create a new instance of that contained class automatically when you
have an instance of the containing class

Yes, but you can compile such a code without new. But in the example
I showed, it would not even compile without a new.

For example, see here (from the same code). Note the "Internal_ICl"
is "local" and cannot access any outer class member, hence will not
compile if you try, but the other inner (nested) classes can, because
of their placement in the code, even regardless of instantiation
('new'), since they all use 'new'.

*/

public int[] interfaceFunction01NestedOuterClass1()
{
NestedInterClass0 Internal_ICl = new NestedInterClass0();

// BTW: Internal_ICl.// cannot see any outer class
member
here, since 'temp' and 'local', but other inner class
mySeemingViolationInnerClass can!

arr_outerCl = Function01NestedOuterClass1(Internal_ICl);
return arr_outerCl;
}
/*

Also, and somewhat beside the point, base classes are always
implicitly instantiated (it seems to me) when a derived class is
called, so a nested class, like you say, seems to require the same
thing, but it doesn't.

I'm also not clear on why you believe access modifiers would result in
spaghetti code, but that's not related to the above (I think :) ).


True, I'll reserve my rant for another day, but it boils down to too
many choices (which a "GOTO" will also give you).

RL
 
J

Jon Skeet [C# MVP]

raylopez99 said:
Thanks Jon. I'd be happy to, since I'm learning:

This part:

*/

public int MyNICTWOfunction ()
{
NestedOuterClass1 myNOC1 = new NestedOuterClass1(); //
instantiation req'd!
// myNOC1.magic_no = 100000; //can override private
number if you want...
return myNOC1.magic_no; // no overriding, should get
magic_no = 1111111;
}

/*

Without the "new NestedOuterClass1()" you cannot have
"myNOC1.magic_no = 100000;" in the next line.

No, of course you can't - you can't access an object without creating
it. This isn't behaviour which is specific to nested classes or
anything like that though.

But you're using incorrect terminology when you say:
"can override private number if you want". Overriding is part of
polymorphism. You can change the value of the field, but that's nothing
to do with overriding.
 
J

Jon Skeet [C# MVP]

raylopez99 said:
Instantiation of _any_ class is required in order to access instance
members, regardless of where that class is declared. So this is not
particular to the question of nested classes.
I think the important thing here, and perhaps what may be the confusing
aspect, is that having a class declared within another class does not
create a new instance of that contained class automatically when you
have an instance of the containing class

Yes, but you can compile such a code without new. But in the example
I showed, it would not even compile without a new.

For example, see here (from the same code). Note the "Internal_ICl"
is "local" and cannot access any outer class member, hence will not
compile if you try, but the other inner (nested) classes can, because
of their placement in the code, even regardless of instantiation
('new'), since they all use 'new'.

*/

public int[] interfaceFunction01NestedOuterClass1()
{
NestedInterClass0 Internal_ICl = new NestedInterClass0();

// BTW: Internal_ICl.// cannot see any outer class
member
here, since 'temp' and 'local', but other inner class
mySeemingViolationInnerClass can!

arr_outerCl = Function01NestedOuterClass1(Internal_ICl);
return arr_outerCl;
}

You can't see any enclosing class members via Internal_IC1 because it's
not an instance of the enclosing class - it's an instance of the nested
class.

It's not clear to me where you think the difference is though, or what
it's got to do with creating a new object.

Comments in your code like "//second nested inner class, this time
access modifier is public, so this class can access enclosing outer
class private numbers" are completely wrong. A nested class can
*always* access private variables of the enclosing class, regardless of
its own declared access.

I'm afraid your code is too convoluted to make much sense out of it,
but I think you're still a way off understanding what's available.
/*

Also, and somewhat beside the point, base classes are always
implicitly instantiated (it seems to me) when a derived class is
called, so a nested class, like you say, seems to require the same
thing, but it doesn't.

It doesn't require the same thing because an instance of a nested class
is completely different from an instance of an enclosing class. Aside
from the special access available, they're just two completely separate
types.
 
P

Peter Duniho

raylopez99 said:
Yes, but you can compile such a code without new. But in the example
I showed, it would not even compile without a new.

There is no difference. No matter where the class is declared, you
cannot access instance members without an instance of the class.

If you have code that won't compile with "new" -- that is, without
creating an instance -- then that code won't compile no matter where you
put it. The nested class is a red herring; it has nothing do with
whether you can access an instance member.
For example, see here (from the same code). Note the "Internal_ICl"
is "local" and cannot access any outer class member, hence will not
compile if you try, but the other inner (nested) classes can, because
of their placement in the code, even regardless of instantiation
('new'), since they all use 'new'.

I don't understand the code example you've provided. The method is in
your outer class, not the inner class. So it doesn't in any way offer
any insight into what sorts of things can be accessed from within the
inner class.

You seem to be getting confused about an instance having access to
things versus the actual methods within a class having access to things.
Where the instance is created has nothing to do with what it can
access. Only where the methods are declared affects access.
Also, and somewhat beside the point, base classes are always
implicitly instantiated (it seems to me) when a derived class is
called, so a nested class, like you say, seems to require the same
thing, but it doesn't.

Here too you seem to misunderstand what's going on.

First, let's assume when you wrote "when a derived class is called", you
actually mean "when a derived class is instantiated". The reason I say
that is that simply calling a method on a class never implicitly
instantiates any class, base or derived. To call an instance method,
you must already have an instance; to call a method in a class without
an instance, the method must be a static method, and calling that method
will not implicitly instantiate either the derived class or the base class.

So, back to your statement above:

The base class is not a separate instance from the derived class. It's
all part of the same instance. When you instantiate the derived class,
the base class is _part_ of that instance. There's no other implicitly
instantiated instance of the base class; it's part and parcel of the
derived class.

So, when you instantiate the derived class, it's not that the base class
is implicitly instantiated so much as it is that the base class, being
part of the derived class, is explicitly instantiated as part of the
derived class.

Using a classic OOP example: consider the class hierarchy with base
class Human and derived classes Man and Woman. When a Man or Woman is
created, it's not that there's some separate Human that is also created;
the Man or Woman _is_ a Human. By creating a Man or a Woman, you
necessarily create something that is either a Man or is a Woman but
which is always _also_ a Human.

Finally, with respect to the access modifier thing you're looking at,
note that a nested class can derive from a non-nested class. In this
case, _only_ the methods declared in the derived nested class will have
access to the containing class. The base class methods do not gain
access simply by virtue of being inherited from within the containing
class. Again, this is because access has everything to do with where
the method in question is declared, and nothing at all to do with where
the instance is actually instantiated.

Pete
 
R

raylopez99

On Sep 20, 11:27 am, Peter Duniho <[email protected]>
wrote:

[interesting, albeit verbose, thanks]

Well, consider this code then:

//////////// start of code //////////////

class Outer1
{
private int A;
public Outer1(int a)
{
A = a;
}
public class Nested1
{
public void DisplayA(Outer1 o)
{
System.Console.WriteLine("this is A:{0}", o.A);
}
}
}


//////////// middle of code ////////////////////////

public static void MMain2()
{
Outer1 o1 = new Outer1(4);
Outer1.Nested1 n1 = new Outer1.Nested1(); // default
instantiation (not even a member function)
n1.DisplayA(o1); //will print "this is A: 4"
}

////////////// end of code /////////////////////


If you comment out from "middle of code" to"end of code", the stuff
from "start of code" to "middle of code" WILL compile, without a
single "new" instantiation, and it's a nested class. Put that into
your pipe and smoke it! LOL. Of course, it won't 'do anything'
without the MMain2() code, but that's another story--I'm talking about
compile errors.

The secret to successful compiling of this nested class code is a sort
of 'forward reference' (using a C++ term) in the two classes
(enclosing, Outer1, and nested, Nested), namely, the forward reference
of "Outer1 o" in the Nested nested class. BTW, if for some reason one
of the methods in the enclosing class, Outer1, also needed to access
some member variable or function from the nested class, Nested, you
would likewise need such a 'forward reference'. And, contrary to the
implication (in my mind), this is not really a 'access problem' since
this line will not compile if placed in the nested class Nested: int
nested_int = Outer1.A; //won't compile, even with "Outer1." specified
as a prefix

This problem, BTW, and offtopic, is not true for derived-inhereited
classes, but, as has been said, this is a completely seperate topic
that only 'optically' looks similar to this problem in this post, but
I mention it since it does strike a chord in one's mind that can lead
to errors.

Therein is the secret then, and why I was having problems (since this
example was my first nested class--I was avoiding them over the years
for good reason).

In short, to compile a nested and enclosing class, you need to have a
"nexus" between nested and enclosing classes. The "nexus" can be one
of two things:

(1) an instantiation, using 'new' of one or both classes (enclosing
and nested) in both enclosing and nested classes, as per the posters
in this thread, including Pete and Jon, or,

(2) what I said about 'forward reference' above, see the example
above.

I had the same problem once in C++ when I was trying to "link" two
classes, each to one another, before they were instantiated using
'new', and I ended up successfully doing this by using pointers, with
forward references of pointers between the classes.

I consider this post the last word on this subject and deem this
thread closed. Thanks for your replies.

Thus speaketh Ray Lopez. So it is written, so it shall come to pass.

RL
 
J

Jon Skeet [C# MVP]

raylopez99 said:
On Sep 20, 11:27 am, Peter Duniho <[email protected]>
wrote:

[interesting, albeit verbose, thanks]

Well, consider this code then:

If you comment out from "middle of code" to"end of code", the stuff
from "start of code" to "middle of code" WILL compile, without a
single "new" instantiation, and it's a nested class. Put that into
your pipe and smoke it! LOL. Of course, it won't 'do anything'
without the MMain2() code, but that's another story--I'm talking about
compile errors.

Um, that's because you're passing in a reference to an object (the
parameter o).

It's not a "forward reference" - it's just a parameter.

Again, this has *nothing* to do with nested classes.

The reason you can't use Outer1.A is that A is an *instance* variable,
not a *static* variable. Again, nothing to do with nested classes.

I consider this post the last word on this subject and deem this
thread closed.

Well, you can if you like - but it still sounds like you're confused.
Particularly the business you wrote about the "nexus" - it has
*nothing* to do with types being nested or not: if you want to access
an instance member of a type, you need an instance of that type. That's
true of *all* types, no matter *where* you reference them from.
 
P

Peter Duniho

raylopez99 said:
On Sep 20, 11:27 am, Peter Duniho <[email protected]>
wrote:

[interesting, albeit verbose, thanks]

I am amused that you would take the time to observe my post as being
"verbose" and then ramble on yourself.
[...]
If you comment out from "middle of code" to"end of code", the stuff
from "start of code" to "middle of code" WILL compile, without a
single "new" instantiation, and it's a nested class.

So what? The code doesn't need an explicit "new" statement for there to
be an instance. In the code remaining, you pass in an instance of the
class being referenced.
[...]
The secret to successful compiling of this nested class code is a sort
of 'forward reference' (using a C++ term) in the two classes
(enclosing, Outer1, and nested, Nested), namely, the forward reference
of "Outer1 o" in the Nested nested class.

As Jon says, this has absolutely nothing to do with the concept of
forward references in C++. C# doesn't even have the concept of forward
references, because no matter where you declare something, the compiler
will find it. There aren't header files, there's no explicit
preprocessing, etc.

In C++ a forward reference has to do with providing necessary
declarations so that at the point at which the compiler comes across the
code, it knows how to interpret it.

In C# there's no such defined order of processing the code, and so no
such thing as forward references is necessary.

As far as the code you're talking about, there's no "secret" at all.
Class Nested1 has complete access to all members of class Outer1, so in
Nested1.DisplayA the code has complete access to all members of class
Outer1, including Outer1.A. It's not a "secret"...it's just a simple
matter of accessibility.

Just as this code would work:

class Outer1
{
private int A;

public Outer1(int a)
{
A = a;
}

public void DisplayA(Outer1 o)
{
System.Console.WriteLine("this is A:{0}", o.A);
}

public void DisplayA()
{
System.Console.WriteLine("this is A:{0}", A);
}

static public void Test()
{
Outer1 o1 = new(5), o2 = new(10);

o1.DisplayA(o2);
o1.DisplayA();
}
}

So too does the code you posted.

In the above code, if you call the Test() method, you will get the
following output:

this is A:10
this is A:5

In the first DisplayA() method, it uses the value from the object passed
in. In the second DisplayA() method, it uses the value of the instance
used to call the method.

Like I wrote before, access doesn't have anything to do with the
instance. It has to do with the code that's being executed. Even if
you are executing an instance method, its access is not limited to
members within the same instance. All that matters is whether the
method itself (not the instance using the method) has access to the member.

If you create an instance method, then yes...you need an instance of
that class's object to call the method. But that doesn't mean that the
instance is required in order to access some other class's member; all
it means is that you declared the method as an instance method, and so
an instance is required.

If you don't want to require an instance, that's easy: just make the
method static. It has nothing to do with the access modifiers. It has
everything to do with whether the method is an instance method or not.
BTW, if for some reason one
of the methods in the enclosing class, Outer1, also needed to access
some member variable or function from the nested class, Nested, you
would likewise need such a 'forward reference'.

Again, there's no such thing as a forward reference in C#. And if you
wanted Outer1 to be able to access something in Nested1, the access
modifier for that thing in Nested1 would have to be internal or public.
Outer1 doesn't have access to private or protected members of Nested1.

Simply declaring some method within Outer1 that takes a Nested1 object
as a parameter, the converse of what is presented in the code you
posted, would not be sufficient. That alone should emphasize the fact
that it's not the code you posted that makes the difference; it's how
the access modifiers work and _where_ that code exists.
And, contrary to the
implication (in my mind), this is not really a 'access problem' since
this line will not compile if placed in the nested class Nested: int
nested_int = Outer1.A; //won't compile, even with "Outer1." specified
as a prefix

That's right. Because A is not a static member of Outer1. It would
compile if you made A a static member.

The fact that you can create a different compile error using incorrect
syntax doesn't in any way invalidate the fact that the question of
whether Nested1 has access to Outer1 members is exactly an access
problem. That's what "access" is all about.
This problem, BTW, and offtopic, is not true for derived-inhereited
classes, but, as has been said, this is a completely seperate topic
that only 'optically' looks similar to this problem in this post, but
I mention it since it does strike a chord in one's mind that can lead
to errors.

Inheritance and nested classes are completely different concepts. You
are right that it is a mistake to consider behavior in one concept to be
at all relevant to behavior in the other concept.
Therein is the secret then, and why I was having problems (since this
example was my first nested class--I was avoiding them over the years
for good reason).

You are still having problems, IMHO.
In short, to compile a nested and enclosing class, you need to have a
"nexus" between nested and enclosing classes. The "nexus" can be one
of two things:

(1) an instantiation, using 'new' of one or both classes (enclosing
and nested) in both enclosing and nested classes, as per the posters
in this thread, including Pete and Jon, or,

(2) what I said about 'forward reference' above, see the example
above.

There is no such thing as a "forward reference" in C#. The _ONLY_ way
to get at an instance member of ANY class is to have an instance of that
class. You can pass it as a parameter, or it can be a variable (created
locally, kept in a field, etc.), or it can be implicit (when the method
itself is an instance member of the same instance you want to get at and
you call the method using that instance). But no matter what, you
_MUST_ have an instance.

In your example, you are trying to call an instance method, and so you
need an instance of the class. But if all you're doing in that method
is accessing data in some _other_ instance, there's no reason to make
that method an instance method. It could just as easily be a static
method, and as a static method you could call it directly via the class
name (eg "Nested1.DisplayA") without instantiating it.
I had the same problem once in C++ when I was trying to "link" two
classes, each to one another, before they were instantiated using
'new', and I ended up successfully doing this by using pointers, with
forward references of pointers between the classes.

In C++, if you have two class members that reference each other (whether
because you store a class member of a type of the other class, or simply
have a function in the class that uses the type, or whatever), then yes,
you do need a forward reference so that each class knows about the other
class even if you don't have a full class definition compiled yet.

But that has absolutely nothing to do with what's going on here.
I consider this post the last word on this subject and deem this
thread closed. Thanks for your replies.

Thus speaketh Ray Lopez. So it is written, so it shall come to pass.

You may think it's the last word. But all that means is that you are
coding without a clue.

Sorry to put it so bluntly, but you asked a question and then refused to
accept the answers, even though it's pretty clear you don't know what
you're talking about. If you ever want to get good at programming,
that's an attitude you are going to have to abandon.

Pete
 
R

raylopez99

raylopez99 said:
On Sep 20, 11:27 am, Peter Duniho <[email protected]>
wrote:
[interesting, albeit verbose, thanks]

I am amused that you would take the time to observe my post as being
"verbose" and then ramble on yourself.

But my ramble is shorter than yours, in this case shorter is better!
But I appreciate your posts anyway, though they tend to be a bit
simplistic.
[...]
If you comment out from "middle of code" to"end of code", the stuff
from "start of code" to "middle of code" WILL compile, without a
single "new" instantiation, and it's a nested class.

So what? The code doesn't need an explicit "new" statement for there to
be an instance. In the code remaining, you pass in an instance of the
class being referenced.

Exactly! Isn't that what I said? One of TWO ways, the other being a
"new" statement.
[...]
The secret to successful compiling of this nested class code is a sort
of 'forward reference' (using a C++ term) in the two classes
(enclosing, Outer1, and nested, Nested), namely, the forward reference
of "Outer1 o" in the Nested nested class.

As Jon says, this has absolutely nothing to do with the concept of
forward references in C++. C# doesn't even have the concept of forward
references, because no matter where you declare something, the compiler
will find it. There aren't header files, there's no explicit
preprocessing, etc.

Call it what you want, call it macaroni. I'm a rapid coder, not a
software engineer. I'll let you and Donald Knuth fight over the
nomenclature.
In C++ a forward reference has to do with providing necessary
declarations so that at the point at which the compiler comes across the
code, it knows how to interpret it.

In C# there's no such defined order of processing the code, and so no
such thing as forward references is necessary.

As far as the code you're talking about, there's no "secret" at all.
Class Nested1 has complete access to all members of class Outer1, so in
Nested1.DisplayA the code has complete access to all members of class
Outer1, including Outer1.A. It's not a "secret"...it's just a simple
matter of accessibility.

Hold on a minute--you're simply repeating that a nested class has all
the access to the private members of the enclosing class...you could
have said that in one sentence, like I just did. But the issue here
is whether something will compile, not a truism of nested classes.
Just as this code would work:

class Outer1
{
private int A;

public Outer1(int a)
{
A = a;
}

public void DisplayA(Outer1 o)
{
System.Console.WriteLine("this is A:{0}", o.A);
}

public void DisplayA()
{
System.Console.WriteLine("this is A:{0}", A);
}

static public void Test()
{
Outer1 o1 = new(5), o2 = new(10);

o1.DisplayA(o2);
o1.DisplayA();
}
}

Yeah, nice, but there's no nested class in your example. This whole
thread is about nested classes. But I see what you're driving at I
think: that a nested class is like an instantiation of any other
class, and can be treated as such. But this point is trivial, since
the 'big deal' in nested classes is accessibility, in particular when
using access modifiers "protected" and "protected internal" for the
nested class.
So too does the code you posted.

In the above code, if you call the Test() method, you will get the
following output:

this is A:10
this is A:5

In the first DisplayA() method, it uses the value from the object passed
in. In the second DisplayA() method, it uses the value of the instance
used to call the method.

Yes, standard textbook procedure. And when this clashes with nested
class nomenclature, as it surely will (see below), it creates the
disconnect that prompted my original post.
Like I wrote before, access doesn't have anything to do with the
instance. It has to do with the code that's being executed. Even if
you are executing an instance method, its access is not limited to
members within the same instance. All that matters is whether the
method itself (not the instance using the method) has access to the member.

This is a consequence of C#'s confusing use of public/private/
protected for members rather than just for classes, but that's a post
for another day. It's also off-topic to nested classes (this post).
If you create an instance method, then yes...you need an instance of
that class's object to call the method. But that doesn't mean that the
instance is required in order to access some other class's member; all
it means is that you declared the method as an instance method, and so
an instance is required.

If you don't want to require an instance, that's easy: just make the
method static. It has nothing to do with the access modifiers. It has
everything to do with whether the method is an instance method or not.

Actually I did make the method static in some code I haven't posted,
and I had so many compile errors I had to switch to non-static.
Static creates huge problems in your code, for reasons too numerous to
mention, but one is that you cannot seem to inhereit static.
'.
Again, there's no such thing as a forward reference in C#. And if you
wanted Outer1 to be able to access something in Nested1, the access
modifier for that thing in Nested1 would have to be internal or public.
Outer1 doesn't have access to private or protected members of Nested1.

But my book sez to use protected and protected internal for nested
classes Pete! For Pete's sake, who to believe? You or book? Book
sez eye.

[ repetitive stuff deleted--good, but a bit verbose--thanks anyway]
You may think it's the last word. But all that means is that you are
coding without a clue.

Sorry to put it so bluntly, but you asked a question and then refused to
accept the answers, even though it's pretty clear you don't know what
you're talking about. If you ever want to get good at programming,
that's an attitude you are going to have to abandon.

Pete

I don't refuse answers, I make assertions and back them with
evidence. But I don't think your verbose "hand waving" replies are
without value. In fact, I very much appreciate what you say, and it
does jog my mind--kind of like a scoutmaster telling you the basics of
survival. But, it's a little too simplistic for me. Perhaps, since
you are so expert (I'm not doubting you're expert BTW), you've
forgotten how to explain things to beginners. I have that problem
with chess--I'm too advanced to be a good teacher.

BTW, here is what I found in my latest version of the "nested class
problem" (one reason I've avoided using them--they're a pain).

Note carefully the comments below.

RL
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
using System; // Nested class example // September 20, 2007
using System.Collections.Generic;
using System.Text;

namespace nestc001
{
class Outer1
{
private int A;
private int jay;
public int jayouterpublic;
Nested1 myNested1;
public Outer1(int a)
{
//myNested1 = new Nested1(); //compiles OK, but strictly
speaking not needed (see below)

// myNested1.jay2; //won't compile since not on RHS -
error CS0201: Only assignment, call, increment, decrement, and new
object expressions can be used as a statement

int ktemp = myNested1.jay2; //compiles? Yes, since on RHS--
EVEN ALONE!!! (no need for myNested1 = new Nested1(); )[as a practical
matter you'll get a null pointer unless you use 'new', but that's
another matter]

//int ktemp3 = myNested1.jay3; //won't compile; can't
reach jay3 due to access 'private'

A = a;
}
public Outer1()
{
A = 1000; jay = jayouterpublic = 1001;
}
protected internal class Nested1
{
public int jay2;
private int jay3;

//int nested_int = Outer1.A; //won't compile

public Nested1()
{
jay2 = jay3 = 101;

Outer1 myOuter01 = new Outer1(10);

// myOuter01.jay;//? compiles-No! since "alone", and
not on RHS, you get error CS0201

// myOuter01.jayouterpublic;//?compiles? No -you get
error CS0201

jay2 = myOuter01.jay; //compiles? yes, if on RHS

jay2 = myOuter01.jayouterpublic; //compiles? yes, but
only if on RHS

}
public void DisplayA(Outer1 o)
{
//o.jay; //compiles? No, error CS0201
// o.jayouterpublic; //compiles? - no CS0201 error
// o.A;//compiles? No! by itself, needs to be on RHS
int j = o.A;//compiles? Yes, if on RHS--this is
important
System.Console.WriteLine("this is A:{0}", o.A);
}
}
}

}
////////////////////////////////////
 
P

Peter Duniho

raylopez99 said:
But my ramble is shorter than yours, in this case shorter is better!
But I appreciate your posts anyway, though they tend to be a bit
simplistic.

I am amused once again. This time with your statement that my posts
are, at the same time, too simplistic and yet not simple enough to
explain things to a beginner.

For what it's worth, while I readily admit that it is possible to have
too much experience when trying to explain concepts, I have in fact had
a fair amount of ongoing success teaching a variety of things to people,
including C# and .NET topics.

There are certainly better teachers around than I am, but sometimes when
a student isn't "getting it", it's partly their fault too.
[...]
If you comment out from "middle of code" to"end of code", the stuff
from "start of code" to "middle of code" WILL compile, without a
single "new" instantiation, and it's a nested class.
So what? The code doesn't need an explicit "new" statement for there to
be an instance. In the code remaining, you pass in an instance of the
class being referenced.

Exactly! Isn't that what I said? One of TWO ways, the other being a
"new" statement.

No, it's nothing like what you said.

The "forward reference" isn't a way, because no such thing exists in C#,
and in any case what you are calling a "forward reference" is simply an
example of instantiation. The other "way" isn't a way, because it's
silly to think that you would create a new instance just for the purpose
of running some code that doesn't otherwise need an instance. That's a
terrible way to design code.

In any case, _neither_ is actually important with respect to how a
contained class may access members of a containing class. The only
reason an instance is required in the code example you provided is that
you declared the members in a way that requires an instance.

If you intend to be able to access a member without an instance, that's
trivial to do. Just make the member static.
Call it what you want, call it macaroni. I'm a rapid coder, not a
software engineer. I'll let you and Donald Knuth fight over the
nomenclature.

You are free to pick random phrases with existing well-defined meanings
and use them in entirely contexts, of course. But when you do so, keep
in mind that people will either have no idea what you're talking about,
or think you yourself have no idea what you're talking about, or both.
Hold on a minute--you're simply repeating that a nested class has all
the access to the private members of the enclosing class...you could
have said that in one sentence, like I just did.

All due respect, you never said anything like that. You have not made
any statement that would lead us to believe that you actually understand
how the relationship between a containing class and a contained class
works, and especially you have not made any statement that makes clear
that you understand that the existence of an instance has absolutely
nothing to do with accessibility (quite the contrary, you seem to think
it's related somehow).

And yes, I have tried to state the same thing in multiple, different
ways. This is a classic teaching technique, since different students
will respond to different language.
But the issue here
is whether something will compile, not a truism of nested classes.

No. The issue of whether something compiles or not is not at all a
question. You cannot run code that doesn't compile, so getting it to
compile is a given. The goal is not simply to get the code to compile,
it's to get it to WORK.

Based on your original post, the issue very much IS "a truism of nested
classes".
Yeah, nice, but there's no nested class in your example.

You're right, there's not. That's the whole point of the example.
This whole
thread is about nested classes. But I see what you're driving at I
think: that a nested class is like an instantiation of any other
class, and can be treated as such.

No, that's not what I'm driving at. There are at least a couple of
points my example was meant to make:

1) That accessibility of members of a containing class by a
contained class is identical to the accessibility by the containing
class itself.

2) That methods that have access to members of a class can access
those members whether they are operating on the instance implicit in the
call to the method, or on an instance that was passed explicitly to the
method.

You don't need to make a single instance of any class to demonstrate
accessibility, so instantiation really doesn't have anything to do with
accessibility.
But this point is trivial, since
the 'big deal' in nested classes is accessibility, in particular when
using access modifiers "protected" and "protected internal" for the
nested class.

I disagree. First of all, one "big deal" of nested classes is that they
can be treated as closely tied to the containing class. A public nested
class is exposed as something that is "part of" the containing class,
rather than simply being one that works with the containing class. Or
it could be hidden within the containing class (protected or private for
example), used only by the containing class. This prevents the class
from being used inappropriately by other classes, for example.

The fact that the contained class has access to the containing class's
members is not the "big deal". If anything it is, IMHO, simply a
natural consequence of creating a consistent language definition. If a
contained class did not have access to the containing class's members,
most of the reason for making a contained class would still exist.
Yes, standard textbook procedure. And when this clashes with nested
class nomenclature, as it surely will (see below), it creates the
disconnect that prompted my original post.

I don't see any clash. If you would like to demonstrate the "clash",
you should create a more concise, less-ambiguous example and very be
clear about where it is you perceive the "clash" to be.
This is a consequence of C#'s confusing use of public/private/
protected for members rather than just for classes, but that's a post
for another day. It's also off-topic to nested classes (this post).

How can a discussion of access modifiers be off-topic in a thread that
is specifically about access modifiers? And how is C#'s use of access
modifiers different from C++'s similar access modifiers? That is, yes
there are some specific differences, but the basic idea is the same in
both languages.
Actually I did make the method static in some code I haven't posted,
and I had so many compile errors I had to switch to non-static.

Without seeing what you tried, it's hard to know whether you really "had
to switch to non-static". Suffice to say, the code you did post could
easily be fixed with the application of the "static" keyword, without
introducing compiler errors.
Static creates huge problems in your code, for reasons too numerous to
mention, but one is that you cannot seem to inhereit static.

Yes, you can't inherit static classes. In most cases, that is not a
"huge problem" and certainly that doesn't appear to be an issue in the
example of code you've posted.

It is patently false that "static creates huge problems in your code";
in fact, if what you want to do is access something without an instance,
"static" is the only way to solve that and it works very well without
creating any problems at all, never mind "huge" ones.

There are specific limitations of static, but they are hardly "too
numerous to mention".

The fact that you would make that claim simply illustrates how much more
you have to learn about proper use of static classes and members.
But my book sez to use protected and protected internal for nested
classes Pete! For Pete's sake, who to believe? You or book? Book
sez eye.

What book? What _exactly_ does it say? Use "protected" for what?

If your book says something other than what I wrote above and which you
quoted, the book is wrong. The contained class has access to members of
the containing class regardless of access modifier, but the converse is
not true.

I suspect the book does not actually contradict what I wrote, and that
you are simply misunderstanding it.
I don't refuse answers, I make assertions and back them with
evidence.

That's not true. The post to which I replied made false assertions,
backed with code that didn't have anything to do with what you were
claiming, never mind support your assertions. And you very much did
refuse the answers that had been given to you.
[...]
BTW, here is what I found in my latest version of the "nested class
problem" (one reason I've avoided using them--they're a pain).

Perhaps you are finding them to be a pain because you are misusing them.
Note carefully the comments below.

I have. I don't understand what point you're trying to make, and I
especially don't understand your desire to obfuscate whatever point it
is you _are_ trying to make with a bunch of pointless statements (that
is, every CS0201 error line that you included, none of which have
anything to do with the question of nested classes or access modifiers).

As far as the specific comments go...
RL
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
using System; // Nested class example // September 20, 2007
using System.Collections.Generic;
using System.Text;

namespace nestc001
{
class Outer1
{
private int A;
private int jay;
public int jayouterpublic;
Nested1 myNested1;
public Outer1(int a)
{
//myNested1 = new Nested1(); //compiles OK, but strictly
speaking not needed (see below)

It _is_ strictly needed if you intended to use the myNested1 variable to
call an instance method in the Nested1 class.
// myNested1.jay2; //won't compile since not on RHS -
error CS0201: Only assignment, call, increment, decrement, and new
object expressions can be used as a statement

Why would you want such a statement anyway?
int ktemp = myNested1.jay2; //compiles? Yes, since on RHS--
EVEN ALONE!!! (no need for myNested1 = new Nested1(); )[as a practical
matter you'll get a null pointer unless you use 'new', but that's
another matter]

This is a great example of why just because the code compiles, that
doesn't mean you've done something that makes sense.
//int ktemp3 = myNested1.jay3; //won't compile; can't
reach jay3 due to access 'private'

Indeed. As I've said already, the containing class does not have access
to private members in the contained class.
A = a;
}
public Outer1()
{
A = 1000; jay = jayouterpublic = 1001;
}
protected internal class Nested1
{
public int jay2;
private int jay3;

//int nested_int = Outer1.A; //won't compile

No, of course not. A is an instance member and as such requires an
instance. If you want to refer to A using the class name, you need to
make A static.
public Nested1()
{
jay2 = jay3 = 101;

Outer1 myOuter01 = new Outer1(10);

// myOuter01.jay;//? compiles-No! since "alone", and
not on RHS, you get error CS0201

Again, so? Why would you want that line of code anyway?
// myOuter01.jayouterpublic;//?compiles? No -you get
error CS0201
Ditto.

jay2 = myOuter01.jay; //compiles? yes, if on RHS

Of course. As I wrote, the contained class has access to private
members of the containing class.
jay2 = myOuter01.jayouterpublic; //compiles? yes, but
only if on RHS

This would compile anywhere, since Outer1.jayouterpublic is a public member.
}
public void DisplayA(Outer1 o)
{
//o.jay; //compiles? No, error CS0201

Again, a useless line of code. Why is the fact that any of these don't
compile of any value in this discussion?
// o.jayouterpublic; //compiles? - no CS0201 error
Ditto.

// o.A;//compiles? No! by itself, needs to be on RHS

Ditto. For the sixth time.
int j = o.A;//compiles? Yes, if on RHS--this is
important

Of course this compiles. The contained class has access to all members
of the containing class, regardless of the access modifier for the
member of the containing class.
System.Console.WriteLine("this is A:{0}", o.A);
Ditto.

}
}
}

}
////////////////////////////////////

So. What was the point in any of the code? What is it that you're
trying to demonstrate? In what way does the above code support your
statement that "nested classes are a pain"?

Pete
 
J

Jon Skeet [C# MVP]

raylopez99 said:
Call it what you want, call it macaroni.

That's a *really* dangerous attitude. Ignoring standard terminology is
a recipe for disaster - it's only through shared terminology that we
can communicate.
I'm a rapid coder, not a software engineer.

That's an even more dangerous attitude - it smacks of not caring about
doing things the most appropriate way or learning how things really
work.

Yeah, nice, but there's no nested class in your example. This whole
thread is about nested classes. But I see what you're driving at I
think: that a nested class is like an instantiation of any other
class, and can be treated as such. But this point is trivial, since
the 'big deal' in nested classes is accessibility, in particular when
using access modifiers "protected" and "protected internal" for the
nested class.

It's *not* a trivial point, as you were claiming that nested classes
acted differently to normal classes in terms of needing your odd
"nexus" idea.
Yes, standard textbook procedure. And when this clashes with nested
class nomenclature, as it surely will (see below), it creates the
disconnect that prompted my original post.

Nope, there's no clash at all.
Actually I did make the method static in some code I haven't posted,
and I had so many compile errors I had to switch to non-static.

You shouldn't change things between being static and non-static just to
fix compilation errors. Things should be static if they logically
belong to the type rather than any particular instance, and vice versa.
Static creates huge problems in your code, for reasons too numerous to
mention, but one is that you cannot seem to inhereit static.

Um, using static members doesn't create huge problems when there's a
good reason for them being static. You just need to understand what it
means.
But my book sez to use protected and protected internal for nested
classes Pete! For Pete's sake, who to believe? You or book? Book
sez eye.

Did the book give any reasoning? If not, I would take it with a pinch
of salt. I tend to make nested classes private and give them internal
methods to access from the enclosing class.

I don't refuse answers, I make assertions and back them with
evidence.

In this case you made assertions which were completely false though.

BTW, here is what I found in my latest version of the "nested class
problem" (one reason I've avoided using them--they're a pain).

It doesn't show the "nested class problem" at all, because the errors
you're showing would occur trying to reference a non-nested class too.
(Some would be access errors rather than errors of "you can't use a
field access as a statement on its own", but that's about it.)

Error CS0201 has nothing to do with nested classes.
 
R

raylopez99

So. What was the point in any of the code? What is it that you're
trying to demonstrate? In what way does the above code support your
statement that "nested classes are a pain"?

Pete

Thanks for commenting my code example. It suppliments what I learned
by by myself.

Bottom line: nested classes are a pain and "composite classes" are
better, as is "inhereited classes", except in those rare instances
where you want the nested class to access the private members of the
containing class.

Bye

RL
 
J

Jon Skeet [C# MVP]

Bottom line: nested classes are a pain and "composite classes" are
better, as is "inhereited classes", except in those rare instances
where you want the nested class to access the private members of the
containing class.

Nested classes are useful in a number of situations, and are no more
"painful" than normal classes. Comparing them to composition and
inheritance is a complete red herring, because they're used for very
different purposes.

Occasionally it's very handy to have access to private members in the
enclosing class, but *also* making a nested class gives an indication
of the context in which a class is relevant.

Jon
 
R

raylopez99

Nested classes are useful in a number of situations, and are no more
"painful" than normal classes. Comparing them to composition and
inheritance is a complete red herring, because they're used for very
different purposes.

Not a "complete" red herring--not a red herring at all. Just an
observation. Use precise language Jon--that way we can communicate
better, remember? ;-)

Occasionally it's very handy to have access to private members in the
enclosing class, but *also* making a nested class gives an indication
of the context in which a class is relevant.

Jon

Your first reason I've already stated. Your second reason is very
lame IMO--you can communicate much better using a comment-- /// in XML
format.

Bottom line is that I doubt I use nested classes much more, any more
than I use Enums for example (int enums, since byte enums are handy as
flags). What completely confused me with nested classes is that I did
not realize they are instantiated just like any two independent
classes--or a composite class (Class A having as a member a class B)--
I assumed nested classes were like base class inherietance--big
mistake.

RL
 
P

Peter Duniho

raylopez99 said:
Not a "complete" red herring--not a red herring at all.

No. "Complete" is definitely the qualifier needed here.

Nested classes are not at all like composition or inheritance, nor are
they used for the same sort of reasons. Any comparison of nested
classes to composition or inheritance is very much a red herring.
Just an observation.

It's an incorrect observation. And personally, I think it odd that you
would consider those language features somehow related, given what you
wrote at the end of your post (see below).
[...]
Your first reason I've already stated. Your second reason is very
lame IMO--you can communicate much better using a comment-- /// in XML
format.

Ahh, yes. Let's abandon language features and structure OOP design
altogether. After all, we can simply document all relationships between
all of the code and all of the data just by putting in comments.

Um, no. As I stated before, the access aspect of nested classes is a
relatively minor part of the usefulness of nested classes. They would
be nearly as useful even without that.
Bottom line is that I doubt I use nested classes much more, any more
than I use Enums for example (int enums, since byte enums are handy as
flags). What completely confused me with nested classes is that I did
not realize they are instantiated just like any two independent
classes--or a composite class (Class A having as a member a class B)--
I assumed nested classes were like base class inherietance--big
mistake.

If you understand now that nested classes are nothing like class
inheritance, why is it that you continue to insist that compositing and
inheritance are "better"? How can it be "better"? As you've already
noted, nested classes do something completely different from compositing
and inheritance.

Saying that inheritance is better than nested classes is like me saying
that my pencil is better than my toothbrush. Neither is "better" than
the other; they are used for completely different purposes.

Pete
 
R

raylopez99

If you understand now that nested classes are nothing like class
inheritance, why is it that you continue to insist that compositing and
inheritance are "better"? How can it be "better"? As you've already
noted, nested classes do something completely different from compositing
and inheritance.

Yes, indeed. I thought nested classes were like a sort of class
access modifier, and worked similar to inhereitance. But they are
simply a mechanism to defeat information hiding of private members in
the enclosing class--a step backwards IMO from encapsulation.
Saying that inheritance is better than nested classes is like me saying
that my pencil is better than my toothbrush. Neither is "better" than
the other; they are used for completely different purposes.

But if you're a writer, a pencil *is* better than a toothbrush. And
for this reason inhereitance and composition *is* better than nested
classes. The former are the bread and butter of OOP.

My last post in this thread; thanks for your help.

RL
 
P

Peter Duniho

raylopez99 said:
Yes, indeed. I thought nested classes were like a sort of class
access modifier, and worked similar to inhereitance.

And as you see, they are neither.
But they are
simply a mechanism to defeat information hiding of private members in
the enclosing class

That is just not true. Nested classes do NOT exist as "simply a
mechanism to defeat information hiding". The access to the containing
class is only a natural side-effect of the consistent design of nested
classes. Since a nested class is by definition a _part_ of the
containing class, then just as every other member that is a part of the
containing class has access to private members, so too does the nested
class.

In my opinion, this is a very natural and clean design. However,
regardless of what you think about that aspect of the design, it is just
silly to claim that nested classes exist solely for that purpose. As I
have said repeatedly, nested classes would be nearly as useful even
without access to the containing class's members.
[...]
But if you're a writer, a pencil *is* better than a toothbrush.

What an absurd statement to make. If you had written "if you are
writing", you might have had a true statement. But that statement would
have solidly reinforced my point, since as I've said, nested classes are
relevant to a specific purpose, so of course they are "better" for a
specific purpose than something not intended for that purpose.

It's true that inheritance is a "better" solution for addressing the OOP
technique of inheriting functionality than are nested classes. But
that's only because nested classes don't have anything to do with
inheriting functionality. You could just as correctly say that nested
classes are a "better" solution for addressing the OOP technique of
encapsulating data structures than is inheritance.

But that doesn't mean that either technique is actually literally better
than the other. It just means that you use the technique designed for a
specific goal when trying to achieve that goal.

By writing "if you're a writer", you've made a completely silly
statement. Writers have just as much use for a toothbrush as they do
for a pencil. They don't use the toothbrush for writing (one hopes),
but they still need to brush their teeth.

That is, in fact, the point of my analogy.
And
for this reason inhereitance and composition *is* better than nested
classes. The former are the bread and butter of OOP.

And nested classes are too. They just address different issues than do
inheritance and composition. Since nested classes are for a completely
different purpose, they are neither "better" nor "worse" than
inheritance and composition. They are simply _different_.
My last post in this thread;

You've said that before. :)
thanks for your help.

You're welcome.

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