December 22, 2012
On 12/22/12 3:21 AM, Walter Bright wrote:
> It's that way in C++ mainly so that it doesn't make the already complex
> overloading system even more so. And in 25 years of working with C++,
> I've never seen this make anyone's list of horrible things about C++.

I think this is a fallacious argument because it concludes that apples should be peeled because oranges should. The impossibility to define a symbol really private in D will lead to awkward idioms like prefixing every private symbol with _p_ or something.


Andrei
December 22, 2012
On 12/22/12 6:13 AM, Dmitry Olshansky wrote:
> See e.g. Boost c++, as an example of code using this _workaround_
> everywhere.

http://boost.2283326.n4.nabble.com/Name-of-namespace-detail-td2667953.html

Andrei

December 22, 2012
On Saturday, 22 December 2012 at 08:47:44 UTC, Jonathan M Davis wrote:
> Pretty much every time that this issue comes up, people are surprised by the
> fact that private symbols aren't hidden and pretty much no one wants them to
> be in overload sets. I think that you're the only one that I've seen post that
> they thought that the current behavior is a good idea (certainly, anyone who
> agrees with you is in the minority or is silent on the issue). What we
> currently have leaks implementation detalis and thus causes code breakage when
> the implementation is changed. It needs to be fixed.
>
> - Jonathan M Davis

I had no idea this was going on. If "private" symbols are not really private then they shouldn't be called private because that is very misleading and can lead to subtle mistakes that will be difficult to understand and avoid.

When I've defined something to be private, I really expect it to be private to the outside, or at best a friend within the same module.

--rt
December 22, 2012
On Saturday, December 22, 2012 20:11:25 Rob T wrote:
> I had no idea this was going on. If "private" symbols are not really private then they shouldn't be called private because that is very misleading and can lead to subtle mistakes that will be difficult to understand and avoid.
> 
> When I've defined something to be private, I really expect it to be private to the outside, or at best a friend within the same module.

They're private in the same way that they're private in C++. They're inaccessible (i.e. can't be called), but they're not actually hidden. Accessibility is only taken into account after overloading has been sorted out. About the only place I'm aware of that this has any practical effect in C++ is the fact that you can overload private functions (which doesn't affect D, because private functions are never virtual in D). If they were actually hidden, you couldn't. Everywhere else, the difference is academic - primarily because only classes have any concept of access level.

In D, on the other hand, the problem is very much _not_ academic, because rather than having a global namespace, we have modules, and each of those modules has access levels for its symbols. We also have UFCS, which effectively makes it possible to add member functions to a class or struct without its permission, which isn't possible in C++. So, in D, it becomes possible to have functions which are inaccessible but which are quite visible and are considered in overload sets along with accessible functions. Because accessibility is determined _after_ the overloading is sorted out, simply adding a private function to your module or class can break existing code in other modules, because you've changed the overload set, causing there to be a name clash or resulting in a function which better matches the set of arguments in one of the calls to it but which then results in an error, because the new function is uncallable. Similarly, it makes private aliases useless, because it pollutes other modules just as much as public aliases do.

So, the situation is _very_ different from C++ even though the way that access levels are handled is essentially the same. And pretty much everyone calls foul as soon as they figure out that that's what's going on. Most people initially don't have any clue about it anymore than most people do with C++, because it's not how people think.  In C++, many people never figure it out. Only more knowledgeable C++ probgrammers are likely to know, because the difference is almost entirely academic. But in D, many programmers find out about it because they run into problems because of it, and I don't think that I've ever seen anyone other than Walter who thought that it was a good idea. But unfortunately, no one has been able to convince Walter of the need to change things yet.

A couple of related bug reports are:

http://d.puremagic.com/issues/show_bug.cgi?id=1238 http://d.puremagic.com/issues/show_bug.cgi?id=2991

I thought that there was one with a lengthier discussion on it, but that's all that I could find at the moment.

And here's another thread on the issue:

http://forum.dlang.org/post/mailman.266.1329071322.20196.digitalmars- d@puremagic.com

- Jonathan M Davis
December 22, 2012
On Saturday, 22 December 2012 at 20:24:54 UTC, Jonathan M Davis wrote:
> They're private in the same way that they're private in C++. They're
> inaccessible (i.e. can't be called), but they're not actually hidden.
> Accessibility is only taken into account after overloading has been sorted
> out. About the only place I'm aware of that this has any practical effect in
> C++ is the fact that you can overload private functions (which doesn't affect
> D, because private functions are never virtual in D). If they were actually
> hidden, you couldn't. Everywhere else, the difference is academic - primarily
> because only classes have any concept of access level.
[snip]

Thanks for taking the time to explain all that. The thread on the subject was a very interesting read and is a eye opener for me because I was mostly unaware of the issue. I'm happy I now know about it because it is something you have to know about otherwise you can run into difficult to understand problems.

So the problem is that "private" affects accessibility but does not affect visibility, and for various practical reasons most people will prefer it to affect (by limiting) visibility in a similar way as it does with accessibility.

Here's my thinking,

After we've installed the new development process, one of the things I am hoping we can work towards cleaning up, is the methods used for maintaining the D specification so that it is done in a much more efficient and accessible way.

Also the process for making decisions that affect the specification are not at all clear and seems to follow an ad-hoc method of endless discussions, often to no effect with poor retention, and that is a *lot* of wasted effort, so this is an area where a clear formalized process can have a lot of benefit for the community in terms of making it operate much more effectively given the limited resources.

Perhaps at some point after the next dmd version is released and stabilized, will be a good time to start working on implementing a process for managing the D specification, assuming of course we have enough consensus that this is a priority area in need of a solution. I sure hope most people think so!

--rt

December 23, 2012
On 12/22/2012 12:46 AM, Jonathan M Davis wrote:
> Pretty much every time that this issue comes up, people are surprised by the
> fact that private symbols aren't hidden and pretty much no one wants them to
> be in overload sets.

This has been discussed before, and the same people wanted private functions removed from overload sets in classes.

So why does this never come up in C++ if it's such a problem? Like I said, I've never seen this come up on peoples' lists of what they don't like about C++, and it isn't because they're shy about complaining about C++ :-)
December 23, 2012
On 12/22/2012 8:03 AM, Andrei Alexandrescu wrote:
> I think this is a fallacious argument because it concludes that apples should be
> peeled because oranges should.

Given, in C++:

struct S
{
  public:
     void foo(int);
  private:
     void foo(float);
}

void bar()
{
    S s;
    s.foo(1.0f);
}

This is an error in C++:

foo.cpp:6: error: âvoid S::foo(float)â is private

(I used g++ so nobody would complain this is a defect in dmc++.)

Why does this never come up on peoples' complaints about C++? I spent some time googling it, and came up with nothing.

I don't think it can be dismissed as fallacious unless the why's have a rationale.


December 23, 2012
On 12/22/2012 6:35 PM, Walter Bright wrote:
> On 12/22/2012 8:03 AM, Andrei Alexandrescu wrote:
>> I think this is a fallacious argument because it concludes that apples should be
>> peeled because oranges should.
>
> Given, in C++:
>
> struct S
> {
>    public:
>       void foo(int);
>    private:
>       void foo(float);
> };

err, forgot the semicolon

December 23, 2012
On Saturday, December 22, 2012 18:35:47 Walter Bright wrote:
> On 12/22/2012 8:03 AM, Andrei Alexandrescu wrote:
> > I think this is a fallacious argument because it concludes that apples should be peeled because oranges should.
> 
> Given, in C++:
> 
> struct S
> {
>    public:
>       void foo(int);
>    private:
>       void foo(float);
> }
> 
> void bar()
> {
>      S s;
>      s.foo(1.0f);
> }
> 
> This is an error in C++:
> 
> foo.cpp:6: error: âvoid S::foo(float)â is private
> 
> (I used g++ so nobody would complain this is a defect in dmc++.)
> 
> Why does this never come up on peoples' complaints about C++? I spent some time googling it, and came up with nothing.
> 
> I don't think it can be dismissed as fallacious unless the why's have a rationale.

Probably because both functions are in the same place, and C++ is far less picky about implicit conversions, meaning that it's _much_ more likely to simply select the public function rather than complain about a conflict (though as your code demonstrates, such a conflict is still possible). Contrast this with D where the compiler is extremely quick to give you an error about functions conflicting rather than trying to guess which one you meant.

Also, with C++, this is restricted to the class that you're dealing with. Derived classes generally won't have the problem (if they overload foo, it'll just call the derived one IIRC rather than complaining about the private one in the base class). So, any breakage you get is directly related to that class. Whereas in D, simply adding a private function to a module can cause a conflict with a completely different module. Such functions in C++ wouldn't even be visible, because they'd be hidden in the cpp file, so you only get that problem when you add more "public" functions (quotes, since there aren't really any access levels for free functions in C++).

In addition, in my experience, it's quite rare for classes to have public and private functions with the same name, meaning that you just don't hit this problem very often. That's probably why it doesn't garner many complaints in C++. Contrast this with D, where with modules, it's trivial to have completely unrelated free functions with the same name which end up conflicting where one is private and another is public. At least with a class, the functions would be related. With modules, the functions are likely to be completely unrelated and much more like to be written by completely different people.

I don't think that D programmers generally complain about this with classes, though UFCS will probably increase those complaints. They mostly complain about this with modules - a problem that C++ doesn't have. And it's the module situation which desparately needs to be fixed. But UFCS will make it so that the problem crops up far more with classes as well, since now anyone can effectively add a function to a class, potentially causing conflicts not only with other functions used with UFCS but also causing problems when the class maintainer adds private functions to the class which would conflict. In C++, you can only get a conflict with derived classes, and in general, the overload rules there make it so that it's not a problem if the public function being clashed with is overridden in the derived class. And more of the problems that you do have are less obvious when they happen and are hard to catch due to C++'s greater laxity with implicit conversions and overload selection.

So, while C++ has the problem, it's on a much, much smaller scale - hence why you don't see a lot of complaints about it in C++. Whereas in D, it happens rather frequently, so plenty of people complain. So, I really think that we would be far better off to make it so that inaccessible functions are never in overload sets. Carrying overy C++'s behavior in this case is just going to cause us grief.

- Jonathan M Davis
December 23, 2012
On 12/21/2012 11:19 PM, Jonathan M Davis wrote:
> but generally the worst that
> they'll do is create slight overhead because of the cost of default
> initializing them.

This is not an issue. An optimization called "dead assignment elimination" has been in compilers since the 1980's, including dmd.