www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - private keyword dont appear to do anything

reply LunaticWare <exemple gmail.com> writes:
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
Nov 03 2017
next sibling parent reply rikki cattermole <rikki cattermole.co.nz> writes:
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
Nov 03 2017
next sibling parent LunaticWare <exemple gmail.com> writes:
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
Nov 03 2017
prev sibling next sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
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
Nov 03 2017
parent reply Nathan S. <no.public.email example.com> writes:
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.
Nov 03 2017
next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
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.
Nov 03 2017
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
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
Nov 03 2017
next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
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 -- Государство делает вид, что платит нам зарплату, а мы делаем вид, что работаем.
Nov 03 2017
prev sibling next sibling parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
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
Nov 03 2017
prev sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
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.
Nov 03 2017
parent reply Paolo Invernizzi <paolo.invernizzi gmail.com> writes:
On Friday, 3 November 2017 at 23:32:52 UTC, H. S. Teoh wrote:
 [...]
What's wrong with the introduction of another visibility attribute that behave like the C++ private? Just curious... --- Paolo
Nov 04 2017
parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Saturday, November 04, 2017 11:03:52 Paolo Invernizzi via Digitalmars-d-
learn wrote:
 On Friday, 3 November 2017 at 23:32:52 UTC, H. S. Teoh wrote:
 [...]
What's wrong with the introduction of another visibility attribute that behave like the C++ private? Just curious...
Well, if a good enough DIP could be written to convince Walter and Andrei, then I'm sure it could be added, but it probably isn't worth it. If you really want that level of separation, then you can always just put your class or struct in its own module, and in practice, the fact that other stuff in a module _could_ access the private members of a struct or class doesn't tend to be a problem - and adding yet another access modifier does make the language and its implementation that much more complicated. It also might break existing code that uses type introspection and has logic based on what access level a symbol has. Ultimately, while I don't think that there's any technical reason why we couldn't make such a change, I think that it's trying to solve a problem that doesn't really exist, and for the change to be made, a solid argument would have to be made as to why it's a real problem that needs fixing and why the proposed solution is the right one. - Jonathan M Davis
Nov 04 2017
prev sibling parent Basile B. <b2.temp gmx.com> writes:
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,
Pascal has "strict private". I like it because you can enforce the usage of setters and getters within the same module. To have strict privacy in D we have to isolate the "strict" thing in a file.
Nov 04 2017
prev sibling next sibling parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Friday, November 03, 2017 16:32:52 H. S. Teoh via Digitalmars-d-learn 
wrote:
 <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.)
Actually, when Daniel and I were trying to talk Walter into adding the package.d feature so that std.datetime could be split up without breaking code, Walter made a comment about how he didn't see any problem with there being a function per module. So, he might be on board with code arrangements along those lines, but I have no idea about Andrei. Personally, I think that splitting stuff up that far makes it a pain to deal with, even if it might help the implementation sometimes. It's already really annoying that I have to figure out which module something in std.algorithm is in now, because the style check junk that has been added to Phobos requires that you not only use selective imports but that you use the module that it's directly in, so you can't do something like import std.algorithm : map; but instead have to go figure out which module it's currently living in and add that after std.algorithm. Of course, I also don't generally have a problem with large modules. They _can_ become large enough to become a problem, but I've found that I have a much higher tolerance for how much goes in a single file than many of the D devs seem to have. IMHO, the main thing that starts causing problems with large modules is when you start doing stuff like using attribute labels like safe: or attribute blocks like safe { } because then it becomes difficult to know which attributes actually apply to a piece of code. Most stuff is self-contained enough that having a bunch of stuff in a single module frequently isn't a real problem. So, if they're related enough, I have no problem with it. But good organization is arguably difficult to get right and highly subjective - just like naming stuff is. Where you risk running into serious problems is where you have a large module full of interdependent stuff, because then it's all highly coupled and hard to keep track of, so it becomes hard to understand and maintain. You can have the same problems across modules, but when you split stuff up across modules, it tends to force you to think about things differently so that you don't make everything so highly coupled - though a bad programmer (or a good programmer having a bad day) can make any code a mess. - Jonathan M Davis
Nov 03 2017
prev sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Fri, Nov 03, 2017 at 05:59:20PM -0600, Jonathan M Davis via
Digitalmars-d-learn wrote:
 On Friday, November 03, 2017 16:32:52 H. S. Teoh via Digitalmars-d-learn 
 wrote:
 <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.)
Actually, when Daniel and I were trying to talk Walter into adding the package.d feature so that std.datetime could be split up without breaking code, Walter made a comment about how he didn't see any problem with there being a function per module. So, he might be on board with code arrangements along those lines, but I have no idea about Andrei.
I got chastised by Andrei for doing the std.algorithm split. He only conceded after I stated that I couldn't run the std.algorithm unittests on my PC anymore because it was taking up GBs of memory. Based on that I'm assuming he would likely be opposed to yet another refactoring of std.algorithm. :-D
 Personally, I think that splitting stuff up that far makes it a pain
 to deal with, even if it might help the implementation sometimes. It's
 already really annoying that I have to figure out which module
 something in std.algorithm is in now, because the style check junk
 that has been added to Phobos requires that you not only use selective
 imports but that you use the module that it's directly in, so you
 can't do something like
 
 import std.algorithm : map;
 
 but instead have to go figure out which module it's currently living
 in and add that after std.algorithm.
If we split everything into its own module, presumably the module would be named after the function itself, and would inherit directly from the top-level std.algorithm package. So it would be a simple matter of going to std/algorithm/${function_name}.d to find the code, which arguably would be *simpler* than it is today. But again, I'm not seriously proposing this, and I doubt we'd actually do it anyway. The sheer amount of effort involved, plus potential user code breakage (explicit imports of std.algorithm.searching, for example, would break, unless we keep searching.d around as just a bunch of public imports, which is kinda ugly), yielding only marginal benefits. I just don't see W & A approving of something like that. [...]
 Where you risk running into serious problems is where you have a large
 module full of interdependent stuff, because then it's all highly
 coupled and hard to keep track of, so it becomes hard to understand
 and maintain.  You can have the same problems across modules, but when
 you split stuff up across modules, it tends to force you to think
 about things differently so that you don't make everything so highly
 coupled - though a bad programmer (or a good programmer having a bad
 day) can make any code a mess.
[...] "Real Programmers can write assembly code in any language." :-D T -- Winners never quit, quitters never win. But those who never quit AND never win are idiots.
Nov 03 2017