Encapsulation

3 views
Skip to first unread message

Jon Harrop

unread,
May 24, 2008, 12:07:16 AM5/24/08
to

I have two separate classes and would like the members of one class to have
access to the private members of another class. What is the idiomatic C#
solution to this?

I believe C++ would use "friends".

--
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com/products/?u

Peter Duniho

unread,
May 24, 2008, 12:24:48 AM5/24/08
to
On Fri, 23 May 2008 21:07:16 -0700, Jon Harrop <j...@ffconsultancy.com>
wrote:

> I have two separate classes and would like the members of one class to
> have
> access to the private members of another class. What is the idiomatic C#
> solution to this?
>
> I believe C++ would use "friends".

It doesn't exist in C#.

You can come close with the "internal" keyword. In that access modifier,
every class within the same assembly would be equivalent to being a
"friend", except that private and protected members would still be
hidden. You'd use "internal" on the members that you really want to share.

Alternatively, nested classes have access to private members of the
containing class(es). But IMHO that's only an appropriate solution if the
nested class really makes sense as a nested class. I wouldn't use it just
to address some accessibility issue.

Pete

Arne Vajhøj

unread,
May 24, 2008, 10:45:39 AM5/24/08
to
Jon Harrop wrote:
> I have two separate classes and would like the members of one class to have
> access to the private members of another class. What is the idiomatic C#
> solution to this?
>
> I believe C++ would use "friends".

The typical C# solution would be to put the classes in same
assembly and use "internal" accessibility.

The most similar to C++ friend would be if they use
"internal" accessibility and are in different assemblies, but
use the InternalsVisibleTo attribute - see details at:

http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.internalsvisibletoattribute.aspx

Arne

Jon Harrop

unread,
May 24, 2008, 5:43:49 PM5/24/08
to
Arne Vajhøj wrote:
> Jon Harrop wrote:
>> I have two separate classes and would like the members of one class to
>> have access to the private members of another class. What is the
>> idiomatic C# solution to this?
>>
>> I believe C++ would use "friends".
>
> The typical C# solution would be to put the classes in same
> assembly and use "internal" accessibility.

That only restricts accessibility to the million lines of other code that
happens to be in the same assembly, which is such a weak constraint as to
be of no practical use.

Arne Vajhøj

unread,
May 24, 2008, 5:59:35 PM5/24/08
to
Jon Harrop wrote:
> Arne Vajhøj wrote:
>> Jon Harrop wrote:
>>> I have two separate classes and would like the members of one class to
>>> have access to the private members of another class. What is the
>>> idiomatic C# solution to this?
>>>
>>> I believe C++ would use "friends".
>> The typical C# solution would be to put the classes in same
>> assembly and use "internal" accessibility.
>
> That only restricts accessibility to the million lines of other code that
> happens to be in the same assembly, which is such a weak constraint as to
> be of no practical use.

I don't think millions of lines of C# code in one assembly
is good at all.

Arne

Jon Harrop

unread,
May 24, 2008, 6:34:23 PM5/24/08
to

Whether I have one line or a million lines, the idea of restricting
accessibility to a single-level (the assembly) does not scale. Moreover, if
I reduce the size of my assemblies then I increase the probability
that "internal" cannot work because access is required from another
assembly.

Jon Harrop

unread,
May 24, 2008, 6:35:12 PM5/24/08
to
Jon Harrop wrote:
> I have two separate classes and would like the members of one class to
> have access to the private members of another class. What is the idiomatic
> C# solution to this?
>
> I believe C++ would use "friends".

Thank you for everyone's responses. The answer appears to be that C# is
unable to express this.

For anyone who is interested, here is a simple example of the kind of
encapsulation that I am referring to (written in OCaml):

module Counter : sig
module Incr : sig
val incr : unit -> unit
val get_n : unit -> int
end
module Adder : sig
val add : int -> unit
end
end = struct
module Incr : sig
val incr : unit -> unit
val get_n : unit -> int
val set_n : int -> unit
end = struct
let n = ref 0
let incr() = incr n
let get_n() = !n
let set_n m =
n := m
end
module Adder = struct
let add m =
Incr.set_n (Incr.get_n() + m)
end
end;;

Note how Counter.Incr.n is used in Counter.Adder.add but is not visible
outside Counter because the Incr module has two different signatures.

Perhaps a better way to explain that in C#-speak is: Counter.Incr.n is
private to Counter.Incr but Counter.Incr.set_n is private to Counter.

Arne Vajhøj

unread,
May 24, 2008, 6:55:24 PM5/24/08
to
Jon Harrop wrote:
> Arne Vajhøj wrote:
>> Jon Harrop wrote:
>>> Arne Vajhøj wrote:
>>>> Jon Harrop wrote:
>>>>> I have two separate classes and would like the members of one class to
>>>>> have access to the private members of another class. What is the
>>>>> idiomatic C# solution to this?
>>>>>
>>>>> I believe C++ would use "friends".
>>>> The typical C# solution would be to put the classes in same
>>>> assembly and use "internal" accessibility.
>>> That only restricts accessibility to the million lines of other code that
>>> happens to be in the same assembly, which is such a weak constraint as to
>>> be of no practical use.
>> I don't think millions of lines of C# code in one assembly
>> is good at all.
>
> Whether I have one line or a million lines, the idea of restricting
> accessibility to a single-level (the assembly) does not scale.

It scales fine.

But it means that the source code and the assemblies are not
independent.

> Moreover, if
> I reduce the size of my assemblies then I increase the probability
> that "internal" cannot work because access is required from another
> assembly.

Well - we have give you the solution to that problem. If you choose
not to use that, then it is your problem not .NET's.

Arne

Jon Harrop

unread,
May 24, 2008, 7:04:31 PM5/24/08
to
Arne Vajhøj wrote:
> Jon Harrop wrote:
>> Whether I have one line or a million lines, the idea of restricting
>> accessibility to a single-level (the assembly) does not scale.
>
> It scales fine.

If it scaled then I would be able to nest assemblies and mark data
as "internal" to the current or any parent assembly. But I cannot => it
does not scale.

Perhaps you mean that it is still possible to write monumental code bases in
the absence of decent encapsulation mechanisms. I cannot disagree with
that.

Arne Vajhøj

unread,
May 24, 2008, 7:18:13 PM5/24/08
to
Jon Harrop wrote:
> Arne Vajhøj wrote:
>> Jon Harrop wrote:
>>> Whether I have one line or a million lines, the idea of restricting
>>> accessibility to a single-level (the assembly) does not scale.
>> It scales fine.
>
> If it scaled then I would be able to nest assemblies and mark data
> as "internal" to the current or any parent assembly. But I cannot => it
> does not scale.
>
> Perhaps you mean that it is still possible to write monumental code bases in
> the absence of decent encapsulation mechanisms. I cannot disagree with
> that.

I assume you mean "I cannot agree" or "I disagree".

If you look out in the real world, then you will see that
somehow people are able to write software with lots
of assemblies without the ability to have a "nested
assembly" mechanism.

Arne

Peter Duniho

unread,
May 24, 2008, 7:30:48 PM5/24/08
to
On Sat, 24 May 2008 15:34:23 -0700, Jon Harrop <j...@ffconsultancy.com>
wrote:

>> I don't think millions of lines of C# code in one assembly


>> is good at all.
>
> Whether I have one line or a million lines, the idea of restricting
> accessibility to a single-level (the assembly) does not scale.

That word "scale". You seem to think it means something other than what
it means.

> Moreover, if
> I reduce the size of my assemblies then I increase the probability
> that "internal" cannot work because access is required from another
> assembly.

Huh? If access is required from another assembly, you add the attribute
Arne suggested, so that the other assembly has access.

I agree it's not a perfect solution, but IMHO "friend" is overused
anyway. Most of the time I see someone wanting to make their classes
"friends", they are heading down the wrong path in the first place.

In any case, as has been explained: this is what C# offers. If you think
it's completely unsuitable to your needs, you need to use a different
language. C++ still has "friend" and you can use that with .NET if you're
still trying to write a .NET program.

Pete

Jon Harrop

unread,
May 24, 2008, 7:27:31 PM5/24/08
to
Arne Vajhøj wrote:
> Jon Harrop wrote:
>> Perhaps you mean that it is still possible to write monumental code bases
>> in the absence of decent encapsulation mechanisms. I cannot disagree with
>> that.
>
> I assume you mean "I cannot agree" or "I disagree".

No, I meant what I said. Consider it roughly equivalent to "I agree with
that".

> If you look out in the real world, then you will see that
> somehow people are able to write software with lots
> of assemblies without the ability to have a "nested
> assembly" mechanism.

Absolutely. Many of our competitors are bumbling around with enormous
Fortran 77 codebases that have no encapsulation or high-level structure at
all.

Tolerating the same deficiencies would mean commercial suicide for us.

Jon Harrop

unread,
May 24, 2008, 7:31:32 PM5/24/08
to

I just had an idea of how it might be possible to workaround this deficiency
in C#. You can try to rewrite your code such that C#'s notion of "private
to this class only" is sufficient by pushing data up the class hierarchy.
Then you can pretend the data is actually in its logical place low in the
class hierarchy by implementing a property in that class.

I don't think that covers the general case but it might be sufficient for my
purposes. Our internal code will be hideous but at least it will present a
usable API for our customers.

Arne Vajhøj

unread,
May 24, 2008, 8:12:22 PM5/24/08
to
Jon Harrop wrote:
> Arne Vajhøj wrote:
>> If you look out in the real world, then you will see that
>> somehow people are able to write software with lots
>> of assemblies without the ability to have a "nested
>> assembly" mechanism.
>
> Absolutely. Many of our competitors are bumbling around with enormous
> Fortran 77 codebases that have no encapsulation or high-level structure at
> all.
>
> Tolerating the same deficiencies would mean commercial suicide for us.

I was talking about .NET code even though I also know about
some Fortran code.

But one size does not fit all. Maybe C# and .NET is not
suitable for your apps.

Arne

Jon Harrop

unread,
May 24, 2008, 8:30:14 PM5/24/08
to
Arne Vajhøj wrote:
> Jon Harrop wrote:
>> Absolutely. Many of our competitors are bumbling around with enormous
>> Fortran 77 codebases that have no encapsulation or high-level structure
>> at all.
>>
>> Tolerating the same deficiencies would mean commercial suicide for us.
>
> I was talking about .NET code even though I also know about
> some Fortran code.
>
> But one size does not fit all. Maybe C# and .NET is not
> suitable for your apps.

Fortunately there are other .NET languages. Unfortunately, the all share
deficiency AFAIK...

Peter Duniho

unread,
May 24, 2008, 8:37:27 PM5/24/08
to
On Sat, 24 May 2008 17:30:14 -0700, Jon Harrop <j...@ffconsultancy.com>
wrote:

> [...]


>> But one size does not fit all. Maybe C# and .NET is not
>> suitable for your apps.
>
> Fortunately there are other .NET languages. Unfortunately, the all share
> deficiency AFAIK...

You started this thread by writing "I believe C++ would use "friends"".
Assuming that's actually the behavior you want, why not just use C++?

Pete

Jon Harrop

unread,
May 24, 2008, 8:51:06 PM5/24/08
to
Jon Harrop wrote:
> I just had an idea of how it might be possible to workaround this
> deficiency in C#. You can try to rewrite your code such that C#'s notion
> of "private to this class only" is sufficient by pushing data up the class
> hierarchy. Then you can pretend the data is actually in its logical place
> low in the class hierarchy by implementing a property in that class.
>
> I don't think that covers the general case but it might be sufficient for
> my purposes. Our internal code will be hideous but at least it will
> present a usable API for our customers.

Actually that doesn't help at all: it is just resorting to completely
unstructured programming because you still have no way to restrict
accessibility to the properties.

So forget that... :-(

Jon Harrop

unread,
May 24, 2008, 9:10:31 PM5/24/08
to
Peter Duniho wrote:
> You started this thread by writing "I believe C++ would use "friends"".
> Assuming that's actually the behavior you want...

That is not the behaviour I want. I only drew the comparison because I hoped
people here might be familiar with C++. My later comparison with OCaml is
precise.

The problem is essentially that "private" can only be used to mean "private
to the current class" in C# and there is no way to express "private to my
parent class" and so on.

> why not just use C++?

The obvious reasons:

. It is not practically feasible to rewrite the code base in another
language.

. C++ has other (far more serious) deficiencies.

. Cross-language development would probably introduce more problems than it
would solve.

etc.

Peter Duniho

unread,
May 24, 2008, 9:28:39 PM5/24/08
to
On Sat, 24 May 2008 18:10:31 -0700, Jon Harrop <j...@ffconsultancy.com>
wrote:

> Peter Duniho wrote:


>> You started this thread by writing "I believe C++ would use "friends"".
>> Assuming that's actually the behavior you want...
>
> That is not the behaviour I want. I only drew the comparison because I
> hoped
> people here might be familiar with C++. My later comparison with OCaml is
> precise.
>
> The problem is essentially that "private" can only be used to mean
> "private
> to the current class" in C# and there is no way to express "private to my
> parent class" and so on.

That's not exactly true. As I mentioned earlier, nested classes have
access to private members in their containing classes.

Whether that addresses your question or not, I can't say. I don't know
OCaml and I'm still trying to decipher that example (honestly, what makes
you think you can post an example in an obscure language like that to a C#
newsgroup and think it's an effective way of getting your point across is
beyond me), so maybe it doesn't.

>> why not just use C++?
>
> The obvious reasons:

Forgive me if I don't see them as obvious, especially given your original
question.

> . It is not practically feasible to rewrite the code base in another
> language.

You'd only need to rewrite the parts that need this functionality.

> . C++ has other (far more serious) deficiencies.

Every language is a compromise. You need to pick what's most important to
you.

> . Cross-language development would probably introduce more problems than
> it
> would solve.

I doubt that. Once you've got a compiled, managed assembly, it doesn't
really matter what language you wrote the code in.

Anyway, I'll keep looking at that OCaml example and try to figure out
exactly what it is you're trying to do.

Pete

Jon Harrop

unread,
May 24, 2008, 9:51:13 PM5/24/08
to
Peter Duniho wrote:
> On Sat, 24 May 2008 15:34:23 -0700, Jon Harrop <j...@ffconsultancy.com>
> wrote:
>>> I don't think millions of lines of C# code in one assembly
>>> is good at all.
>>
>> Whether I have one line or a million lines, the idea of restricting
>> accessibility to a single-level (the assembly) does not scale.
>
> That word "scale". You seem to think it means something other than what
> it means.

I mean "scale" in the mathematical sense: as program size increases the
utility of that approach tends to zero.

>> Moreover, if
>> I reduce the size of my assemblies then I increase the probability
>> that "internal" cannot work because access is required from another
>> assembly.
>
> Huh? If access is required from another assembly, you add the attribute
> Arne suggested, so that the other assembly has access.

Sure but you are still trying to use a flat sequence of assemblies to
represent a hierarchy of constraints.

> I agree it's not a perfect solution, but IMHO "friend" is overused
> anyway. Most of the time I see someone wanting to make their classes
> "friends", they are heading down the wrong path in the first place.

I am actually translating from ML and not C++. In ML, you can refine
interfaces (called signatures) hierarchically and the result is clear,
simple and scales flawlessly.

> In any case, as has been explained: this is what C# offers. If you think
> it's completely unsuitable to your needs, you need to use a different
> language. C++ still has "friend" and you can use that with .NET if you're
> still trying to write a .NET program.

I just want to be absolutely sure that there isn't some whizz-bang feature
in C# that beautifully solves that problem but that I had overlooked.

Peter Duniho

unread,
May 24, 2008, 10:09:49 PM5/24/08
to
On Sat, 24 May 2008 15:35:12 -0700, Jon Harrop <j...@ffconsultancy.com>
wrote:

> Jon Harrop wrote:


>> I have two separate classes and would like the members of one class to
>> have access to the private members of another class. What is the
>> idiomatic
>> C# solution to this?
>>
>> I believe C++ would use "friends".
>
> Thank you for everyone's responses. The answer appears to be that C# is
> unable to express this.
>
> For anyone who is interested, here is a simple example of the kind of
> encapsulation that I am referring to (written in OCaml):

My first thought is: inasmuch as one can say that different languages
exist for different reasons, it seems to me that just because you can do
something in a language like OCaml, it's not clear you should expect to be
able to do it in some other language. At the very least, there seems to
be some greater implicit connection between the OCaml modules you posted
than there would be between classes in C#.

That said, I agree that it doesn't seem like this has anything to do with
the functional aspect of OCaml, but rather just how accessibility is
determined. With that in mind, some other thoughts:

> [...]


> Note how Counter.Incr.n is used in Counter.Adder.add but is not visible
> outside Counter because the Incr module has two different signatures.
>
> Perhaps a better way to explain that in C#-speak is: Counter.Incr.n is
> private to Counter.Incr but Counter.Incr.set_n is private to Counter.

With respect to the code you posted, my first observation is that I'm not
really clear why you put the actual counter in your Incr module. If Incr
was defined to just be the thing that does the incrementing, you could put
the counter itself in the Counter module. From an OOP point of view, this
makes more sense to me. YMMV.

If you do that, then you solve the accessibility issue simply by moving
the counter to a place where both nested classes can get at it:

public class Counter
{
private int n { get; set; }

public class Incr
{
public void incr(Counter counter) { counter.n += 1; }
}

public class Adder
{
public void add(Counter counter, int m) { counter.n += m; }
}
}

Alternatively, you could use interfaces to keep part of your Incr class
private, even as you make some of it public. Here is an example of a
Counter class that contains a private implementation of Incr that is
accessible to Adder, but which implements the public interface IIncr that
only publishes the incr() method:

public interface IIncr
{
void incr();
}

public class Counter
{
public Counter()
{
Incr = new IncrClass();
Adder = new AdderClass(this);
}

public readonly AdderClass Adder;
private readonly IncrClass Incr;
public IIncr IIncr { get { return Incr; } }

// This class is private, so that only other Counter members
// can see the entire API
private class IncrClass : IIncr
{
public int n { get; set; }

public void incr() { n += 1; }
}

// This class could be private too, but since we're not trying
// to hide anything, making it public saves having us need to
// make another interface declaration :)
public class AdderClass
{
public AdderClass(Counter counter)
{
this.counter = counter;
}

private readonly Counter counter;

public void add(int m) { counter.Incr.n += m; }
}
}

Since I'm not fluent in OCaml, I don't know for sure that either of the
above are similar enough to what you posted. If not, then I would suggest
using something other than OCaml to demonstrate your point. Even if you
simply posted C# that doesn't compile, but which is what you'd _expect_,
as long as you also explain what the part of the C# code that doesn't
compile is supposed to be doing, I think that'd be a better example than a
language that practically none of us have ever used. :)

Pete

Jon Harrop

unread,
May 24, 2008, 10:16:32 PM5/24/08
to
Peter Duniho wrote:
> On Sat, 24 May 2008 18:10:31 -0700, Jon Harrop <j...@ffconsultancy.com>
> wrote:
>> Peter Duniho wrote:
>>> You started this thread by writing "I believe C++ would use "friends"".
>>> Assuming that's actually the behavior you want...
>>
>> That is not the behaviour I want. I only drew the comparison because I
>> hoped
>> people here might be familiar with C++. My later comparison with OCaml is
>> precise.
>>
>> The problem is essentially that "private" can only be used to mean
>> "private
>> to the current class" in C# and there is no way to express "private to my
>> parent class" and so on.
>
> That's not exactly true. As I mentioned earlier, nested classes have
> access to private members in their containing classes.

Exactly, yes.

Starting from my OCaml solution you can identify the more globally private
definitions in Incr ("n" and "set_n") and push the them up the class
hierarchy without changing the API. In this case, move them into Counter:

module Counter : sig
module Incr : sig
val incr : unit -> unit
val get_n : unit -> int
end
module Adder : sig
val add : int -> unit
end
end = struct

let n = ref 0

let set_n m =
n := m

module Incr = struct


let incr() = incr n
let get_n() = !n

end
module Adder = struct
let add m =

set_n (Incr.get_n() + m)
end
end;;

From an external point of view this provides exactly the same interface as
my original solution but there is now only one global interface for "Incr"
so this solution can be expressed directly in C#.

However, the logically related definitions "n", "set_n" and "get_n" that
were nicely encapsulated in the Incr module are now scattered across the
class hierarchy, their locations dictated by how "private" they are.

> Whether that addresses your question or not, I can't say. I don't know
> OCaml and I'm still trying to decipher that example (honestly, what makes
> you think you can post an example in an obscure language like that to a C#
> newsgroup and think it's an effective way of getting your point across is
> beyond me), so maybe it doesn't.

I'm sorry but I can see no better way to convey the problem.

Jon Harrop

unread,
May 24, 2008, 11:21:39 PM5/24/08
to
Peter Duniho wrote:
> On Sat, 24 May 2008 15:35:12 -0700, Jon Harrop <j...@ffconsultancy.com>
> wrote:
>> For anyone who is interested, here is a simple example of the kind of
>> encapsulation that I am referring to (written in OCaml):
>
> My first thought is: inasmuch as one can say that different languages
> exist for different reasons, it seems to me that just because you can do
> something in a language like OCaml, it's not clear you should expect to be
> able to do it in some other language. At the very least, there seems to
> be some greater implicit connection between the OCaml modules you posted
> than there would be between classes in C#.
>
> That said, I agree that it doesn't seem like this has anything to do with
> the functional aspect of OCaml, but rather just how accessibility is
> determined.

Exactly, yes. This is a characteristic of the module system and has nothing
to do with functional programming.

> With that in mind, some other thoughts:
>
>> [...]
>> Note how Counter.Incr.n is used in Counter.Adder.add but is not visible
>> outside Counter because the Incr module has two different signatures.
>>
>> Perhaps a better way to explain that in C#-speak is: Counter.Incr.n is
>> private to Counter.Incr but Counter.Incr.set_n is private to Counter.
>
> With respect to the code you posted, my first observation is that I'm not
> really clear why you put the actual counter in your Incr module. If Incr
> was defined to just be the thing that does the incrementing, you could put
> the counter itself in the Counter module. From an OOP point of view, this
> makes more sense to me. YMMV.

Yes. You would almost certainly remove Incr and Adder entirely but that is
changing the problem rather than solving it! :-)

> ...


> public interface IIncr
> {
> void incr();
> }
>
> public class Counter
> {
> public Counter()
> {
> Incr = new IncrClass();
> Adder = new AdderClass(this);
> }
>
> public readonly AdderClass Adder;
> private readonly IncrClass Incr;
> public IIncr IIncr { get { return Incr; } }
>
> // This class is private, so that only other Counter members
> // can see the entire API
> private class IncrClass : IIncr
> {
> public int n { get; set; }
>
> public void incr() { n += 1; }
> }
>
> // This class could be private too, but since we're not trying
> // to hide anything, making it public saves having us need to
> // make another interface declaration :)
> public class AdderClass
> {
> public AdderClass(Counter counter)
> {
> this.counter = counter;
> }
>
> private readonly Counter counter;
>
> public void add(int m) { counter.Incr.n += m; }
> }
> }

This does not expose the correct API because the counter cannot be read from
outside the Counter class. However, I've been fiddling with this for the
past hour and derived the following solution from it which I think is
correct:

public class Counter
{
private int n { get; set; }

public Counter()
{
Incr = new IncrClass(this);
Adder = new AdderClass(this);
}

public readonly AdderClass Adder;
public readonly IncrClass Incr;

public class IncrClass
{
public IncrClass(Counter counter) { this.counter = counter; }
private readonly Counter counter;
public int n { get { return counter.n; } }
public void incr() { counter.n += 1; }
}

public class AdderClass
{
public AdderClass(Counter counter) { this.counter = counter; }
private readonly Counter counter;

public void add(int m) { counter.n += m; }
}
}

This preserves my original API, with a getter and incrementer for the
counter in Counter.Incr and an adder in Adder. The counter itself has been
pushed up from Incr into Counter to make it private over a wider area
(including Adder). The critical point is that a property in Counter.Incr is
used to make it look as if the counter is still there from the point of
view of everything outside Counter.

So I think this satisfies all of my requirements and, although it requires
duplication, I think it is much cleaner than using "internal" and trying to
decompose a big program into separate assemblies to achieve the same
effect.

In general terms, you take ML code with refined interfaces and rewrite it by
moving definitions to be as global as possible without widening their
accessibility. Then you implement a property/member where they were to make
it look as if they never moved.

> Since I'm not fluent in OCaml, I don't know for sure that either of the
> above are similar enough to what you posted. If not, then I would suggest
> using something other than OCaml to demonstrate your point. Even if you
> simply posted C# that doesn't compile, but which is what you'd _expect_,
> as long as you also explain what the part of the C# code that doesn't
> compile is supposed to be doing, I think that'd be a better example than a
> language that practically none of us have ever used. :)

Actually it looks like OCaml turned out to be the best representation here.
Thanks very much for your help!

Peter Duniho

unread,
May 25, 2008, 1:17:29 AM5/25/08
to
On Sat, 24 May 2008 20:21:39 -0700, Jon Harrop <j...@ffconsultancy.com>
wrote:

> [...]


> This does not expose the correct API because the counter cannot be read
> from
> outside the Counter class. However, I've been fiddling with this for the
> past hour and derived the following solution from it which I think is

> correct: [snip]

You could have just changed the IncrClass property and associated
interface so that the getter was public. Then the counter could have
stayed in the IncrClass (assuming that was important to you). Or for that
matter simply used a different name for the internal/shared/whatever
property than the external/public/whatever property, the latter having
only a getter, and the former being as in my example.

> [...]


> Actually it looks like OCaml turned out to be the best representation
> here.

I guess that depends on your point of view. From where I'm sitting, your
OCaml example was VERY difficult to turn into something that explained
your problem.

No doubt it was very easy for you to create the example, so from your
point of view, you got what you wanted with a minimum of effort on your
part. But that doesn't mean it was the best representation.

> Thanks very much for your help!

You're welcome. :)

Pete

Jon Harrop

unread,
May 25, 2008, 6:58:42 AM5/25/08
to
Peter Duniho wrote:
> On Sat, 24 May 2008 20:21:39 -0700, Jon Harrop <j...@ffconsultancy.com>
> wrote:
>> This does not expose the correct API because the counter cannot be read
>> from
>> outside the Counter class. However, I've been fiddling with this for the
>> past hour and derived the following solution from it which I think is
>> correct: [snip]
>
> You could have just changed the IncrClass property and associated
> interface so that the getter was public. Then the counter could have
> stayed in the IncrClass (assuming that was important to you). Or for that
> matter simply used a different name for the internal/shared/whatever
> property than the external/public/whatever property, the latter having
> only a getter, and the former being as in my example.

How could you make the setter accessible to AdderClass (i.e. it cannot be
private to IncrClass) but inaccessible from outside Counter (i.e. it cannot
be public either) without moving it out of IncrClass?

Peter Duniho

unread,
May 25, 2008, 6:13:06 PM5/25/08
to
On Sun, 25 May 2008 03:58:42 -0700, Jon Harrop <j...@ffconsultancy.com>
wrote:

> How could you make the setter accessible to AdderClass (i.e. it cannot be


> private to IncrClass) but inaccessible from outside Counter (i.e. it
> cannot
> be public either) without moving it out of IncrClass?

The setter is already accessible to AdderClass without being accessible
outside Counter. So I think your real question is how to make the
_getter_ accessible outside Counter without making the setter also
accessible. And the answer is, the same way we made the incr() method
accessible without making other parts of IncrClass public: add it (the
getter, and only the getter) to the interface.

In the example I posted, just one more line is needed to allow retrieval
of the actual counter value. To the interface declaration, add:

int n { get; }

Nothing else needed to change, and you would then be able to retrieve "n"
from Counter (via IIncr, same as the "incr()" method).

In fact, the more I look at your OCaml example, the more I think that
interfaces are always going to be the natural C# way to address this
"sig/struct" business in OCaml. If I understand that correctly, the "sig"
part is how the module looks to the outside world, and the "struct" part
is the actual implementation, visible to peers within a module. This is
exactly what the interface/implementation stuff does in C#. The interface
is like the OCaml sig, and the implementation is like the OCaml struct.

Starting with some nested-class implementation that you only want part of
its public API (that is, the part that's public to its peers in the
containing class) to be public to the outside world, you simply create an
interface that describes the parts of the nested-class that you want to be
public to the outside world and leave everything else out.

Pete

Arne Vajhøj

unread,
May 25, 2008, 10:31:56 PM5/25/08
to
Jon Harrop wrote:
> Peter Duniho wrote:
>> You started this thread by writing "I believe C++ would use "friends"".
>> Assuming that's actually the behavior you want...
>
> That is not the behaviour I want. I only drew the comparison because I hoped
> people here might be familiar with C++. My later comparison with OCaml is
> precise.
>
> The problem is essentially that "private" can only be used to mean "private
> to the current class" in C# and there is no way to express "private to my
> parent class" and so on.
>
>> why not just use C++?
>
> The obvious reasons:
>
> . It is not practically feasible to rewrite the code base in another
> language.
>
> . C++ has other (far more serious) deficiencies.
>
> . Cross-language development would probably introduce more problems than it
> would solve.

And it should be noted that friend is not valid in managed types
in C++.

Arne

Arne Vajhøj

unread,
May 25, 2008, 10:34:18 PM5/25/08
to
Jon Harrop wrote:
> Peter Duniho wrote:
>> On Sat, 24 May 2008 15:34:23 -0700, Jon Harrop <j...@ffconsultancy.com>
>> wrote:
>>>> I don't think millions of lines of C# code in one assembly
>>>> is good at all.
>>> Whether I have one line or a million lines, the idea of restricting
>>> accessibility to a single-level (the assembly) does not scale.
>> That word "scale". You seem to think it means something other than what
>> it means.
>
> I mean "scale" in the mathematical sense: as program size increases the
> utility of that approach tends to zero.

Maybe eventually.

But there is no indication of it happening in the .NET framework.

So I would say that it is only a potential problem if you plan
on developing something a couple of magnitudes larger than the
.NET framework.

Arne

Jon Harrop

unread,
May 26, 2008, 1:43:17 AM5/26/08
to
Arne Vajhøj wrote:
> Jon Harrop wrote:
>> Peter Duniho wrote:
>>> On Sat, 24 May 2008 15:34:23 -0700, Jon Harrop <j...@ffconsultancy.com>
>>> wrote:
>>>>> I don't think millions of lines of C# code in one assembly
>>>>> is good at all.
>>>> Whether I have one line or a million lines, the idea of restricting
>>>> accessibility to a single-level (the assembly) does not scale.
>>> That word "scale". You seem to think it means something other than what
>>> it means.
>>
>> I mean "scale" in the mathematical sense: as program size increases the
>> utility of that approach tends to zero.
>
> Maybe eventually.
>
> But there is no indication of it happening in the .NET framework.

What makes you think that?

harborsparrow

unread,
May 26, 2008, 10:00:02 PM5/26/08
to
On May 24, 12:07 am, Jon Harrop <j...@ffconsultancy.com> wrote:
> I have two separate classes and would like the members of one class to have
> access to the private members of another class. What is the idiomatic C#
> solution to this?
>
> I believe C++ would use "friends".
>
> --
> Dr Jon D Harrop, Flying Frog Consultancyhttp://www.ffconsultancy.com/products/?u

If you let both classes inherit from a third superclass, you can use
"protected" to let them see each other's data (I think). I would not
do that, however, without documenting it prominently.

Arne Vajhøj

unread,
May 26, 2008, 10:48:01 PM5/26/08
to
Jon Harrop wrote:
> Arne Vajhøj wrote:
>> Jon Harrop wrote:
>>> Peter Duniho wrote:
>>>> On Sat, 24 May 2008 15:34:23 -0700, Jon Harrop <j...@ffconsultancy.com>
>>>> wrote:
>>>>>> I don't think millions of lines of C# code in one assembly
>>>>>> is good at all.
>>>>> Whether I have one line or a million lines, the idea of restricting
>>>>> accessibility to a single-level (the assembly) does not scale.
>>>> That word "scale". You seem to think it means something other than what
>>>> it means.
>>> I mean "scale" in the mathematical sense: as program size increases the
>>> utility of that approach tends to zero.
>> Maybe eventually.
>>
>> But there is no indication of it happening in the .NET framework.
>
> What makes you think that?

The usability of .NET is nowhere near zero.

Arne

Jon Harrop

unread,
May 27, 2008, 9:28:39 AM5/27/08
to

Sure. That says nothing of the utility of this workaround though.

Jon Harrop

unread,
May 27, 2008, 9:28:53 AM5/27/08
to
harborsparrow wrote:
> If you let both classes inherit from a third superclass, you can use
> "protected" to let them see each other's data (I think). I would not
> do that, however, without documenting it prominently.

I believe a lack of multiple inheritance means that cannot work in general
but the idiomatic C# workaround is to use interfaces however C# does not
yet support access modifiers in interfaces. Is that correct?

Peter Duniho

unread,
May 27, 2008, 2:07:18 PM5/27/08
to
On Tue, 27 May 2008 06:28:53 -0700, Jon Harrop <j...@ffconsultancy.com>
wrote:

> harborsparrow wrote:


>> If you let both classes inherit from a third superclass, you can use
>> "protected" to let them see each other's data (I think). I would not
>> do that, however, without documenting it prominently.
>
> I believe a lack of multiple inheritance means that cannot work in
> general
> but the idiomatic C# workaround is to use interfaces however C# does not
> yet support access modifiers in interfaces. Is that correct?

Technically, yes. But it's not clear what you mean. All interface
members are "public", but interfaces themselves need not be. You can use
the access modifier on the interface itself, nesting the interface as
appropriate, to control access to specific parts of a class.

That said, I already provided a reply to your most recent problem, showing
you how to solve it. At least for the extant example, it doesn't seem as
though having access modifiers within an interface would be needed or
useful in any case.

Pete

Jon Harrop

unread,
May 29, 2008, 5:41:57 AM5/29/08
to
Peter Duniho wrote:
> On Tue, 27 May 2008 06:28:53 -0700, Jon Harrop <j...@ffconsultancy.com>
> wrote:
>> harborsparrow wrote:
>>> If you let both classes inherit from a third superclass, you can use
>>> "protected" to let them see each other's data (I think). I would not
>>> do that, however, without documenting it prominently.
>>
>> I believe a lack of multiple inheritance means that cannot work in
>> general
>> but the idiomatic C# workaround is to use interfaces however C# does not
>> yet support access modifiers in interfaces. Is that correct?
>
> Technically, yes. But it's not clear what you mean. All interface
> members are "public", but interfaces themselves need not be. You can use
> the access modifier on the interface itself, nesting the interface as
> appropriate, to control access to specific parts of a class.

I see. So you might need many separate interfaces for any given class.

> That said, I already provided a reply to your most recent problem, showing
> you how to solve it. At least for the extant example, it doesn't seem as
> though having access modifiers within an interface would be needed or
> useful in any case.

Perhaps it would be more concise?

Peter Duniho

unread,
May 29, 2008, 1:53:27 PM5/29/08
to
On Thu, 29 May 2008 02:41:57 -0700, Jon Harrop <j...@ffconsultancy.com>
wrote:

>>> I believe a lack of multiple inheritance means that cannot work in

>>> general
>>> but the idiomatic C# workaround is to use interfaces however C# does
>>> not
>>> yet support access modifiers in interfaces. Is that correct?
>>
>> Technically, yes. But it's not clear what you mean. All interface
>> members are "public", but interfaces themselves need not be. You can
>> use
>> the access modifier on the interface itself, nesting the interface as
>> appropriate, to control access to specific parts of a class.
>
> I see. So you might need many separate interfaces for any given class.

I wouldn't think so. I mean, sure...if you have a very complex set of
relationships between implementation and clients, with a variety of
clients, each of whom have different accessibility to the implementation,
that might require more than one interface. But it seems to me that as
you enter that area of complexity, it's time to rethink the overall
architecture. That's a _very_ unusual situation and IMHO will practically
always be a sign of a larger issue that needs fixing.

>> That said, I already provided a reply to your most recent problem,
>> showing
>> you how to solve it. At least for the extant example, it doesn't seem
>> as
>> though having access modifiers within an interface would be needed or
>> useful in any case.
>
> Perhaps it would be more concise?

More concise? I don't see how. Do you have an example of a C# syntax
that uses access modifiers in an interface as an alternative to my
proposal (simply adding the getter to the interface) in order to make a
more concise declaration of the code?

Pete

Arne Vajhøj

unread,
May 31, 2008, 11:34:19 PM5/31/08
to
Jon Harrop wrote:
> Arne Vajhøj wrote:
>> Jon Harrop wrote:
>>> Arne Vajhøj wrote:
>>>> Jon Harrop wrote:
>>>>> Peter Duniho wrote:
>>>>>> On Sat, 24 May 2008 15:34:23 -0700, Jon Harrop <j...@ffconsultancy.com>
>>>>>> wrote:
>>>>>>>> I don't think millions of lines of C# code in one assembly
>>>>>>>> is good at all.
>>>>>>> Whether I have one line or a million lines, the idea of restricting
>>>>>>> accessibility to a single-level (the assembly) does not scale.
>>>>>> That word "scale". You seem to think it means something other than
>>>>>> what it means.
>>>>> I mean "scale" in the mathematical sense: as program size increases the
>>>>> utility of that approach tends to zero.
>>>> Maybe eventually.
>>>>
>>>> But there is no indication of it happening in the .NET framework.
>>> What makes you think that?
>> The usability of .NET is nowhere near zero.
>
> Sure. That says nothing of the utility of this workaround though.

It says that the problem you describe does not seem to
have any effect on the total product.

Arne

Jon Harrop

unread,
Jun 1, 2008, 4:34:34 AM6/1/08
to

No, you have simply made a sequence of unrelated statements, none of which
have any bearing on the problem I described.

Your statement "the usability of .NET is nowhere near zero" obviously does
not imply that "there is no indication of it happening in the .NET
framework". Moreover, it has nothing to do with the problem I described.

Your statement "there is no indication of it happening in the .NET
framework" is a claim that you have failed to observe something. You cannot
draw any strong conclusions from failing to find evidence, particularly
when there is no evidence that you have even looked.

By the same logic, "the usability of LAPACK is nowhere near zero" says that
garbage collection does not seem to have any effect on products. That is
absurd, of course.

Barry Kelly

unread,
Jun 1, 2008, 9:15:55 AM6/1/08
to
Jon Harrop wrote:

> I am actually translating from ML and not C++. In ML, you can refine
> interfaces (called signatures) hierarchically and the result is clear,
> simple and scales flawlessly.

> I just want to be absolutely sure that there isn't some whizz-bang feature


> in C# that beautifully solves that problem but that I had overlooked.

Short answer: C# (similarly to Java) simply doesn't provide hierarchical
modules. Classes and assemblies are all you get.

Hierarchically composed modules would be nice and all, but all us folks
in the .NET and Java worlds have been getting along fairly OK without
them up until now.

-- Barry

--
http://barrkel.blogspot.com/

Jon Harrop

unread,
Jun 2, 2008, 4:37:17 AM6/2/08
to

Right, thanks.

Reply all
Reply to author
Forward
0 new messages