Jump to page: 1 2
Thread overview
private keyword dont appear to do anything
Nov 03, 2017
LunaticWare
Nov 03, 2017
rikki cattermole
Nov 03, 2017
LunaticWare
Nov 03, 2017
Jonathan M Davis
Nov 03, 2017
Nathan S.
Nov 03, 2017
H. S. Teoh
Nov 03, 2017
H. S. Teoh
Nov 03, 2017
Jonathan M Davis
Nov 03, 2017
H. S. Teoh
Nov 04, 2017
Paolo Invernizzi
Nov 04, 2017
Jonathan M Davis
Nov 04, 2017
Basile B.
Nov 03, 2017
Jonathan M Davis
Nov 04, 2017
H. S. Teoh
November 03, 2017
hello, being new to D i assumed that the private keyword would work as in C++, but writing this code, i excepted it to throw an error at compile time, it appear to not doing anything, is there something i am doing wrong ?

------
import std.stdio;

class Foo
{
    private int id = 10;
}

struct Bar
{
    private int id = 20;
}

void main()
{
    auto foo = new Foo;
    Bar bar;

    foo.id = 15;
    bar.id = 25;

    writeln(foo.id);
    writeln(bar.id);
}

// RDMD OUTPUT
// 15
// 25

November 03, 2017
Visibility modifiers like private, and public are to the module not the scope.

"Symbols with private visibility can only be accessed from within the same module."

This is how module based languages work, a bit more useful then to the scope approach IMO. An easy mistake to make.

https://dlang.org/spec/attribute.html#visibility_attributes
November 03, 2017
On Friday, 3 November 2017 at 12:43:15 UTC, rikki cattermole wrote:
> Visibility modifiers like private, and public are to the module not the scope.
>
> "Symbols with private visibility can only be accessed from within the same module."
>
> This is how module based languages work, a bit more useful then to the scope approach IMO. An easy mistake to make.
>
> https://dlang.org/spec/attribute.html#visibility_attributes

thank you
November 03, 2017
On Friday, November 03, 2017 13:43:15 rikki cattermole via Digitalmars-d- learn wrote:
> Visibility modifiers like private, and public are to the module not the scope.
>
> "Symbols with private visibility can only be accessed from within the same module."
>
> This is how module based languages work, a bit more useful then to the scope approach IMO. An easy mistake to make.
>
> https://dlang.org/spec/attribute.html#visibility_attributes

To be fair, there are times where it would arguably be desirable to restrict private to a struct or class, so it's not all wonderful, but it does mean that we don't have to have the extra complication of friend functions like C++ does (which I believe is the biggest motivation for it). And if a module is so large that you can't make sure that nothing is accessing private struct or class members when it shouldn't, then the module is probably overly large and/or complicated.

Most folks are surprised by this behavior, and occasionally, they complain about it, but in practice, the only real problem that I'm aware of is that you can sometimes write unit tests which work just because they're in the module, and the code doesn't work when used outside of the module. But even that tends to be only an occasional problem.

- Jonathan M Davis

November 03, 2017
On Friday, 3 November 2017 at 20:01:27 UTC, Jonathan M Davis wrote:
> Most folks are surprised by this behavior

I found it surprising at first but now any other way seems absurd to me. None of the benefits of data encapsulation apply to code written five lines away in the same file.
November 03, 2017
On Fri, Nov 03, 2017 at 09:08:56PM +0000, Nathan S. via Digitalmars-d-learn wrote:
> On Friday, 3 November 2017 at 20:01:27 UTC, Jonathan M Davis wrote:
> > Most folks are surprised by this behavior
> 
> I found it surprising at first but now any other way seems absurd to me.  None of the benefits of data encapsulation apply to code written five lines away in the same file.

This is a good point. :-)

Though in practice, source files do tend to get long... I've had to work with source files over 8000+ lines long, and having encapsulation between two distant parts of the file can be useful.  However, even then, one can argue that any benefits of encapsulation you may have are already negated by the very-not-encapsulated practice of an 8000-line long source file, so the point is moot anyway.


T

-- 
Don't get stuck in a closet---wear yourself out.
November 03, 2017
On 11/3/17 5:08 PM, Nathan S. wrote:
> On Friday, 3 November 2017 at 20:01:27 UTC, Jonathan M Davis wrote:
>> Most folks are surprised by this behavior
> 
> I found it surprising at first but now any other way seems absurd to me. None of the benefits of data encapsulation apply to code written five lines away in the same file.

I also enjoy the mechanism, but I have to call this out as incorrect. Encapsulation is about being able to prove to yourself exactly how an object's private data can possibly be manipulated. It's not just 5 lines away, it's the whole file you have to review.

If you have large flat files like Phobos, then encapsulation is essentially impossible to review.

-Steve
November 03, 2017
On Fri, Nov 03, 2017 at 05:43:55PM -0400, Steven Schveighoffer via Digitalmars-d-learn wrote:
> On 11/3/17 5:08 PM, Nathan S. wrote:
> > On Friday, 3 November 2017 at 20:01:27 UTC, Jonathan M Davis wrote:
> > > Most folks are surprised by this behavior
> > 
> > I found it surprising at first but now any other way seems absurd to me.  None of the benefits of data encapsulation apply to code written five lines away in the same file.
> 
> I also enjoy the mechanism, but I have to call this out as incorrect. Encapsulation is about being able to prove to yourself exactly how an object's private data can possibly be manipulated. It's not just 5 lines away, it's the whole file you have to review.
> 
> If you have large flat files like Phobos, then encapsulation is essentially impossible to review.
[...]

Arguably, many of these large flat files ought to be split up into smaller files.  For example, std.algorithm.* and std.range.* all tend to be conglomerations of basically-independent groups of structs and functions.  Iota and Cycle never interact with each other, and neither of them interacts with Recurrence, yet these all sit in the same file.

Seems to me like a typical case of low cohesion, which, according to the ideals of encapsulation, ought to be grounds for splitting up the file into self-contained parts.

But of course, there are pragmatic reasons for the way things currently are.


T

-- 
Государство делает вид, что платит нам зарплату, а мы делаем вид, что работаем.
November 03, 2017
On Friday, November 03, 2017 14:52:22 H. S. Teoh via Digitalmars-d-learn wrote:
> On Fri, Nov 03, 2017 at 05:43:55PM -0400, Steven Schveighoffer via
Digitalmars-d-learn wrote:
> > On 11/3/17 5:08 PM, Nathan S. wrote:
> > > On Friday, 3 November 2017 at 20:01:27 UTC, Jonathan M Davis wrote:
> > > > Most folks are surprised by this behavior
> > >
> > > I found it surprising at first but now any other way seems absurd to me.  None of the benefits of data encapsulation apply to code written five lines away in the same file.
> >
> > I also enjoy the mechanism, but I have to call this out as incorrect. Encapsulation is about being able to prove to yourself exactly how an object's private data can possibly be manipulated. It's not just 5 lines away, it's the whole file you have to review.
> >
> > If you have large flat files like Phobos, then encapsulation is essentially impossible to review.
>
> [...]
>
> Arguably, many of these large flat files ought to be split up into smaller files.  For example, std.algorithm.* and std.range.* all tend to be conglomerations of basically-independent groups of structs and functions.  Iota and Cycle never interact with each other, and neither of them interacts with Recurrence, yet these all sit in the same file.
>
> Seems to me like a typical case of low cohesion, which, according to the ideals of encapsulation, ought to be grounds for splitting up the file into self-contained parts.
>
> But of course, there are pragmatic reasons for the way things currently are.

If you take that to the extreme, you just end up with a function per module, which is pretty ridiculous IMHO (though that may be what you mean by pragmatic reasons). And really, free functions like that are exactly the sort of places where encapsulation tends not to matter much, because there's nothing to encapsulate beyond the guts of the functions themselves, which are already encapsulated. The situation is very different from something like std.container where you have types which have member variables which could be protected from access by other stuff in their modules if private worked differently.

Figuring out a good way to organize a bunch of free functions is difficult (as evidenced by the fact that plenty of folks have a hard time remembering what is where inside of std.algorithm and std.range), but that's really not an encapsulation problem, just a code organization problem.

- Jonathan M Davis

November 03, 2017
On Fri, Nov 03, 2017 at 04:30:21PM -0600, Jonathan M Davis via Digitalmars-d-learn wrote:
> On Friday, November 03, 2017 14:52:22 H. S. Teoh via Digitalmars-d-learn wrote:
[...]
> > Arguably, many of these large flat files ought to be split up into smaller files.  For example, std.algorithm.* and std.range.* all tend to be conglomerations of basically-independent groups of structs and functions.  Iota and Cycle never interact with each other, and neither of them interacts with Recurrence, yet these all sit in the same file.
> >
> > Seems to me like a typical case of low cohesion, which, according to the ideals of encapsulation, ought to be grounds for splitting up the file into self-contained parts.
> >
> > But of course, there are pragmatic reasons for the way things currently are.
> 
> If you take that to the extreme, you just end up with a function per module, which is pretty ridiculous IMHO (though that may be what you mean by pragmatic reasons).

It's not that ridiculous if you consider that some of the more heavily-used Phobos functions are actually not individual functions, but overload sets.  I know we have been trying to merge some of the unnecessary overload sets for other reasons, but some of these overload sets can get pretty big.  Compound that with the long string of unittests associated with each overload, that has accumulated from a long string of bug fixes, etc., and you have pretty good justification for keeping just that single overload set in its own file, together with its associated unittests, and potentially also other paraphrenalia like enums or other declarations used by the overload set, but not used anywhere else.


> And really, free functions like that are exactly the sort of places where encapsulation tends not to matter much, because there's nothing to encapsulate beyond the guts of the functions themselves, which are already encapsulated.

Arguably, once a function grows past a certain length, it's time to break it down into more manageable pieces.  Having a function sit in its own file gives you a nice working space for this sort of refactoring, without worrying about namespace conflicts with unrelated code.

Still, I agree that some degree of judgment is involved here.  If we're talking about a simple function that will never grow past 5-10 lines, it does seem a little pointless to keep it in its own file, just to adhere to some ideal of encapsulation.

But IME, with Phobos code even simple functions eventually grow into multi-page monsters over time, once you start adding type-specific specializations to deal with performance issues and the like.  Just look at std.algorithm.searching.find, for example.  Several different overloads, and static if blocks within an overload, sometimes on the lengthy side depending on the specific optimization being implemented. Arguably we should factor out some of the static if blocks or overloads into separate private functions for easier future maintenance / management if more specializations are added, or we need to balance between different optimizations based on different factors. Static-if / else blocks just aren't very conducive to this sort of thing.  And being able to do this in a file dedicated to .find would be cleaner than having to do surgery in a 4600-line file (and having to deal with potential merge conflicts with other unrelated changes to the same file -- though git is so good at this that one generally doesn't run into much of a problem).


> The situation is very different from something like std.container where you have types which have member variables which could be protected from access by other stuff in their modules if private worked differently.

Well, std.container *has* been split into submodules per container type. I think that's a much better organization than in std.algorithm.*.


> Figuring out a good way to organize a bunch of free functions is difficult (as evidenced by the fact that plenty of folks have a hard time remembering what is where inside of std.algorithm and std.range), but that's really not an encapsulation problem, just a code organization problem.
[...]

<half-serious> Perhaps the solution is to go the one-overload-set-per-file route, with std/algorithm/package.d basically importing everything underneath. :-P </half-serious>

(Shhh, don't tell Andrei, or we'll get another lecture about wasting time on worthless things while more important things are left to do.)


T

-- 
All problems are easy in retrospect.
« First   ‹ Prev
1 2