July 14, 2006
>> Private members should be totally invisible, because that's the point of
>> marking them private.
> 
> But then the compiler loses the ability to make intelligent error
> messages, right?

No, the compiler obviously still sees them.. But as far as things like overload resolution are concerned, the end result should be the same as if they didn't exist (note that this point is moot if they're all required to be at the same visibility)


>> As for overloading issues, as far as I am concerned, feel free to
>> require all methods with the same name to have the same protection;
>> anything else is poor taste anyway.
> 
> Really? Then how do you hide the previous method implementation?

I'm not sure what you're asking here.. You can override methods as normal. You can also increase visibility, if you want, but once you do it for one method named "foo", you have to do it for all other methods named "foo" as well.

> class A {
>   protected pm() { ... }
> }
> class B : A {
>   // ugly, isn't it :(
>   protected pm() { assert(0); /* subclasses: do not use this */ }
>   public pm2() { super.pm(); ... }
> }

ugly indeed, but not necessary :)

> class A {
>   protected pm() { ... }
> }
> class B : A {
>   public pm() { super.pm(); ... }
> }

All methods in class B called "pm" have the same visibility, so no problem...


xs0
July 14, 2006
xs0 wrote:
> 
>> The original reason why private members would be visible but not accessible has been forgotten. However, there were some significant issues brought up with making them invisible:
>>
>> 1) function overloading - if various overloads of a function have different protections, different functions will be selected even though the same arguments are presented. This can be surprising when code is moved around. If they are visible, you'll get an error message instead of silently varying behavior.
> 
>> 2) function overloading - one could lose the ability to 'poison' an operation on certain argument types, because instead the private function will not be seen and another selected.
> 
>> 3) function overriding - if a private function in a derived class overrides a public one in a base class, this overriding will not happen if the private function is invisible. Not only does this break encapsulation, it prevents the design pattern of being able to 'poison' certain operations on a class.
> 
> Consider
> 
> class Number {
>     public void setVal(int val) { ... }
>     public void setVal(long val) { ... }
> }
> 
> class IntNumber : Number {
>     public void setVal(int val) { ... }
>     private void setVal(long val) { assert(0); }
> }
> 
> Number a = new IntNumber();
> a.setVal(10L);

With 162, it _does_ fail to compile if you move the class definitions to another module. If the code is all in the same module, then the assert trips. Both of these seem to work Ok to me.

> 
> Now, not only does the last line compile, it also calls the wrong function and fails to fail. There is no poisoning or whatever, and the author's belief that he achieved something by declaring something private is misguided. Furthermore, allowing the private declaration above means allowing broking inherited interfaces, practically always a bug.
> 
> Reducing visibility should be forbidden, as it doesn't even work and leads to bugs.
> 
> Private members should be totally invisible, because that's the point of marking them private.
> 

IMHO, that may be a little strong...

IIRC 'protection' is universally termed "access protection" - not just in D but when describing OOP protection generically or specifically for almost any other OOP language. In other words, it specifies 'access' not 'visibility'.

I think this is the first time I've really run into big 'visibility' concerns and can't recall 'visibility' by itself requiring a redesign of either the library or client code that I've written or used. But I do tend to agree it can be unintuitive, and if things could also be made 'invisible' and not break/limit other things than I'm all for it.

If it weren't for the two bugs regarding private module members not really being private, I wonder if this topic would even be a big concern right now.

> As for overloading issues, as far as I am concerned, feel free to require all methods with the same name to have the same protection; anything else is poor taste anyway.
> 
> 
> xs0
July 14, 2006
Walter Bright wrote:
> 
> Sometimes it is valuable to be able to say "you can't do this operation with this type". I don't see why this ability should be restricted to C++.

Can someone come up with an example or explain why this would be valuable? To make sure we're on the same page, we're talking about:

----
class Base {
  public:
    virtual int Number() = 0;
};
...
class Child : public Base {
  private:
    int Number() { return 1; }
};
...
Child c;
int num = c.Number(); //error: cannot access private member
Child* cp = new Child();
num = cp->Number(); //error: cannot access private member
Base* bp = new Child();
num = bp->Number(); // num = 1

----
Is there an example where you can't subvert the poison? In this case can't we get a pointer to the base class which returns what the child class didn't want to give us (private Number)?

...Added to wiki to get better overview (it's easier for me to see rather than jumping all over the newsgroup. Feel free to edit and consolidate views into concrete and concise arguments. I'm starting to feel like a secretary... :)

http://www.prowiki.org/wiki4d/wiki.cgi?PrivateIssues

Lucas
July 14, 2006
>> class Number {
>>     public void setVal(int val) { ... }
>>     public void setVal(long val) { ... }
>> }
>>
>> class IntNumber : Number {
>>     public void setVal(int val) { ... }
>>     private void setVal(long val) { assert(0); }
>> }
>>
>> Number a = new IntNumber();
>> a.setVal(10L);
> 
> With 162, it _does_ fail to compile if you move the class definitions to another module. If the code is all in the same module, then the assert trips. Both of these seem to work Ok to me.

Are you sure? I just checked again and the assert doesn't trip, nor does it fail to compile. Here is the exact code I used:

module main;

import ba;

void main()
{
	Number a = new IntNumber();
	a.setVal(10L);
}
==================
module ba;

class Number {
    public void setVal(int val) { }
    public void setVal(long val) { }
}

class IntNumber : Number {
    public void setVal(int val) { }
    private void setVal(long val) { assert(0); }
}


>> Reducing visibility should be forbidden, as it doesn't even work and leads to bugs.
>>
>> Private members should be totally invisible, because that's the point of marking them private.
> 
> IMHO, that may be a little strong...
> 
> IIRC 'protection' is universally termed "access protection" - not just in D but when describing OOP protection generically or specifically for almost any other OOP language. In other words, it specifies 'access' not 'visibility'.

Well, I've no idea what term is the exactly right one to use, but I wanted to say that outside their defining module, private stuff should have no effects at all on any other code, as if it wasn't there at all.


xs0
July 14, 2006
xs0 wrote:
> 
>>> class Number {
>>>     public void setVal(int val) { ... }
>>>     public void setVal(long val) { ... }
>>> }
>>>
>>> class IntNumber : Number {
>>>     public void setVal(int val) { ... }
>>>     private void setVal(long val) { assert(0); }
>>> }
>>>
>>> Number a = new IntNumber();
>>> a.setVal(10L);
>>
>> With 162, it _does_ fail to compile if you move the class definitions to another module. If the code is all in the same module, then the assert trips. Both of these seem to work Ok to me.
> 
> Are you sure? I just checked again and the assert doesn't trip, nor does it fail to compile. Here is the exact code I used:
> 
> module main;
> 
> import ba;
> 
> void main()
> {
>     Number a = new IntNumber();
>     a.setVal(10L);
> }
> ==================
> module ba;
> 
> class Number {
>     public void setVal(int val) { }
>     public void setVal(long val) { }
> }
> 
> class IntNumber : Number {
>     public void setVal(int val) { }
>     private void setVal(long val) { assert(0); }
> }
> 

Ahhh, I used 'IntNumber a = new IntNumber();' not 'Number a = new IntNumber();' (I didn't copy 'n paste).

But 'a' is a 'Number' and not an 'IntNumber'. D has the same behavior as the equivalent C++ in this case.

If I cast: (cast(IntNumber)a).setVal(10L); with your code then I get the expected results too.

> 
>>> Reducing visibility should be forbidden, as it doesn't even work and leads to bugs.
>>>
>>> Private members should be totally invisible, because that's the point of marking them private.
>>
>> IMHO, that may be a little strong...
>>
>> IIRC 'protection' is universally termed "access protection" - not just in D but when describing OOP protection generically or specifically for almost any other OOP language. In other words, it specifies 'access' not 'visibility'.
> 
> Well, I've no idea what term is the exactly right one to use, but I wanted to say that outside their defining module, private stuff should have no effects at all on any other code, as if it wasn't there at all.
> 
> 
> xs0
July 14, 2006
xs0 wrote:
>>> As for overloading issues, as far as I am concerned, feel free to require all methods with the same name to have the same protection; anything else is poor taste anyway.
>>
>> Really? Then how do you hide the previous method implementation?
> 
> I'm not sure what you're asking here.. You can override methods as normal. You can also increase visibility, if you want, but once you do it for one method named "foo", you have to do it for all other methods named "foo" as well.

Sorry, my bad. I was still thinking about the overrides.

Combining overriding + overloading may lead to very confusing code. Personally I definitely wouldn't want to touch any C++ code that overloads ints, longs and/or chars and overrides them with methods having totally random visibility unless somebody was pointing at me with a loaded shotgun.

Luckily overloading is a bit easier in D. Still, it should first check that all overrides are sane and nothing weird happens when an object is called through different base classes/interfaces.

-- 
Jari-Matti
July 14, 2006
Lucas Goss wrote:
> Walter Bright wrote:
>>
>> Sometimes it is valuable to be able to say "you can't do this operation with this type". I don't see why this ability should be restricted to C++.
> 
> Can someone come up with an example or explain why this would be valuable? To make sure we're on the same page, we're talking about:
> 
> ----
> class Base {
>   public:
>     virtual int Number() = 0;
> };
> ...
> class Child : public Base {
>   private:
>     int Number() { return 1; }
> };

I think it's a bug that the compiler allows this. It should be illegal code, because it breaks encapsulation.
July 15, 2006
Derek Parnell wrote:
> On Fri, 14 Jul 2006 19:30:19 +1000, Walter Bright  <newshound@digitalmars.com> wrote:
> 
>> Ivan Senji wrote:
>>
>>> Various 'poisoning' techniques sound a lot like C++ to me. There one  can make classes that can not be constructed, can not be inherited  from, can not be passed by value, cannot be allocated on stack and many  different things by making something that is private. But are these  techniques realistic or even possible in D?
>>
>>
>> Sometimes it is valuable to be able to say "you can't do this operation  with this type". I don't see why this ability should be restricted to  C++.
> 
> 
> In that case, why not directly support this concept in the language rather  than use 'tricks' or side-effects to do it. If it a worthy thing then say  so.
> 

Just out of personal preference I agree with Derek here.

To me it seems unintuitive to make private visible.  My typical use of private is intended to hide something, not just make it inaccessable. Would there even be a way to make an identifier invisible?  Anyhow, I'd rather private be invisible, and add a "poisoned" keyword or somesuch (better name?).

Overloads by protection also seem dubious IMO.
July 15, 2006
Walter Bright wrote:
> Lucas Goss wrote:
>> Walter Bright wrote:
>>>
>>> Sometimes it is valuable to be able to say "you can't do this operation with this type". I don't see why this ability should be restricted to C++.
>>
>> Can someone come up with an example or explain why this would be valuable? To make sure we're on the same page, we're talking about:
>>
>> ----
>> class Base {
>>   public:
>>     virtual int Number() = 0;
>> };
>> ...
>> class Child : public Base {
>>   private:
>>     int Number() { return 1; }
>> };
> 
> I think it's a bug that the compiler allows this. It should be illegal code, because it breaks encapsulation.

Good. That should be documented in the spec then, that isn't mentioned anywhere, as far as we know.

-- 
Bruno Medeiros - CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
July 15, 2006
Bruno Medeiros wrote:
> 
> Good. That should be documented in the spec then, that isn't mentioned anywhere, as far as we know.
> 

Uh, that was C++ code, sorry I didn't make it clear.

Lucas