July 14, 2006
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++.
July 14, 2006
Walter Bright 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++.

OK, for a type, but would it be inconsistent if private was handled different in class and module level?

I didn't mean it should be restricted to C++ but was rather wondering if there are other/better ways in D?
July 14, 2006
Ivan Senji wrote:
> Walter Bright 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++.
> 
> OK, for a type, but would it be inconsistent if private was handled different in class and module level?
> 
> I didn't mean it should be restricted to C++ but was rather wondering if there are other/better ways in D?

I don't know of a better way.
July 14, 2006
Walter Bright 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++.

Seems to me that it's a bit of a hack to use private for that purpose.
FWIW, you can also use deprecated{} to poison functions (though of course it doesn't work if -d is enabled). Of course this is a hack as well, but interestingly it catches internal use of that function, which AFAIK 'private' does not.

class Something {
deprecated {
  bool opEquals(Something q) { return false; }
}
}

And if IFTI worked for operators, you could write:

class Something {
  bool opEquals(A) (A q) {
	static assert(0,
     "You can't do == with type Something, because ...");
  }
}
July 14, 2006
> 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);

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.

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
Yeah C# has this - its called public readonly. I would like to see it too.

In article <e95nsi$2vkf$1@digitaldaemon.com>, Lucas Goss says...
>
>Was there ever any resolve as to private being visible? I know Walter said he saw the value of private by default, but what about private being visible? It just seems to have dropped off the radar and I don't know if thats good or bad.
>
>Lucas


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);
> 
> Now, not only does the last line compile, it also calls the wrong function and fails to fail.

And casting back to IntNumber makes it again private. No OOP language should do that. It's against the rules of polymorphism.

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

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

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

vs.

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

-- 
Jari-Matti
July 14, 2006
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.

-- 
Derek Parnell
Melbourne, Australia
July 14, 2006
Walter Bright wrote:
> Dave wrote:
>> Everyone seems to agree that 'private' should not be accessible and the current behavior is a bug. What we're all wondering is if 'private' can also mean 'invisible' because that seems to be more intuitive. Than you don't have that extra level of complexity for lookup resolution and things like error messages describing a private interface.
> 
> 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.
> 
Perhaps do as suggested before, disallow overloads with different protections?

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

I didn't get this case, what is this 'poison' design pattern?

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

Same question as above.

But regardless of the answer, perhaps D should disallow the strictening of protection levels (i.e., allow only wider protection), since that seems to be inconsistent behavior from an OO and subtyping point of view? This issue was discussed a bit in a recent D.bugs thread:
http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D.bugs/7649
(news://news.digitalmars.com:119/e7jv87$1a8g$1@digitaldaemon.com)
In particular it was stated that the spec is a bit vague in what kind of behavior is allowed (in regards to overriding and protection levels).

-- 
Bruno Medeiros - CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
July 14, 2006
Jari-Matti Mäkelä wrote:
> 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);
>>
>> Now, not only does the last line compile, it also calls the wrong
>> function and fails to fail.
> 
> And casting back to IntNumber makes it again private. No OOP language
> should do that. It's against the rules of polymorphism.
> 

Agreed, it does seem that contravariant (method) protection levels should not be allowed.

> 
>> 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?
> 
> class A {
>   protected pm() { ... }
> }
> class B : A {
>   // ugly, isn't it :(
>   protected pm() { assert(0); /* subclasses: do not use this */ }
>   public pm2() { super.pm(); ... }
> }
> 
> vs.
> 
> class A {
>   protected pm() { ... }
> }
> class B : A {
>   public pm() { super.pm(); ... }
> }
> 

He said overload, not override.

-- 
Bruno Medeiros - CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D