-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Document privacy of type-fields #12064
Comments
Tagging all fields you want to keep private with a _ is a lot more of a bother than simply adding public/private keywords to the definitions where you can actually get a warning or error if misused. |
@ScottPJones: I think that is a separate issue: language feature vs documentation/convention. (Not sure whether one has been opened yet). |
Field overloading would give the same flexibility to the dot notation as the |
Yes, that should be opened as well. I still stand by my last point, that documenting something that people simply don't follow, or feel is incorrect (see @tknopp's comments about immutables in the same julia-users discussion) isn't going to do much good. The horse has already left the barn. |
I'm in favor of a |
If the default for all fields of a type is private, then you are simply adding 7 characters "public " to those fields. On the other hand, if you use a Also, for 29 years I worked on a language with probably >100,000 programmers using it, and before we added public/private (default private for functions in a module) (which was about 18 years ago, IIRC), we constantly had problems with programmers using internal interfaces, and then complaining that we broke things they depended on. I'd like the programmer community of julians get to be as large or larger, and I'd hope that julia not repeat mistakes I've had to painfully deal with in the past. |
Why do you only consider the PoV of the writer of a library (/piece of code) ? I've been in the opposite situation many times when I'm using someone's code and they made some things private because, after all, it's "good practice" to hide most of your internals. However, I know what I'm doing, I read the source, the compiler could do it but refuses because of some keyword ? In other words, it's not only mindless idiots using your pristine code, sometimes you are also using some mindless idiot's code ;-) |
As currently envisioned, I think |
No, I'm actually considering both. As a user of somebody else's code, I'd like to know just what the real API is, what the contract I have with the module / library / package. If you see that the code you are using does not give you some needed functionality in its API, then you can, depending on if it is open source or not, then you'd file an enhancement request (that's what I would get from customers), for open source, you'd raise an issue (if you don't know how to fix it yourself), or submit a PR (which a smart guy like you would probably do!). For open source, you'd even have the option of forking the darn thing if the author(s) are not responsive (or died, or whatever), and people could start using your new improved version that does have the functionality you want. Mucking around in the internals only helps you, makes your code more fragile, and doesn't help anybody else. Doing the above helps the entire community. I've been on both sides of the fence throughout my career, and I've had to deal with my own share of mindless idiots! (luckily, I haven't seen run into any yet in the julia community [we may disagree, yes, but I do know they are brilliant]) Maybe this could be handled like deprecations. privatewarn == 0 means no warnings, |
The road to C++/Java is paved with good intentions. -1e6 to any sort of |
@ihnorton The problem with that is, it is still just a convention, and is not easy to find out if people are breaking that convention. Also, having to use |
so use setters and getters... |
I tried to follow this already at the mailing list and questioned myself: where did i follow this or the other convention in the last ~30 years of programming? I entered object orientation late and always found the private/public differentiation as something obscure. I understand where it comes from and why it's really, really needed, but in writing code and especially in rapid prototyping it's defining a speed limit. Two things come here to my mind:
tl;dr: a convention for the name that can be checked by a lint should be enough. |
@ihnorton Why would I want the extra complication of adding setters and getters, just to access my own internal structures? That seems like a waste of my time. @lobingera How do you run lint on the programs that hundreds of thousands of people have written, that you have no access to? |
Well, i somehow believe in the superiority of Open Source. Therefore the situation that i have no access to the 'other' code doesn't happen. |
@ScottPJones I'm still in favor of the convention and linting approach cause it seems like the path of least resistance. However, I suppose we could have a |
-1 to language-level enforcement of private/public. This is a language On Wed, Jul 8, 2015 at 11:33 AM, Andreas Lobinger [email protected]
|
Yeah, a huge -1 to mandatory access enforcement from me too. In C++, they only get in the way if you're trying out something new before you know what the right interface is. And if you do know what the right interface is, having to access private fields is a code smell that could be caught by Lint. |
@Rory-Finnegan the convention and linting approach does nothing to help if you don't have access to the code using the modules/packages that you write. Before we added the ability to optionally use public/private tags for functions, properties, and methods, we used to waste a very large amount of time due to customers having abused some code that was supposed to be internal only (to say nothing of the problem of said customers being upset that their wonderful code stopped working). @malmaud Why should julia be limited to scientific computing? That seems very narrow. Julia seems to me to be able to replace C, C++, Java, and Python for most of my programming (and I'm not doing scientific computing). @Keno What is the problem with an optional feature, that the author of a module can use or not as they see fit? Also, if it is controlled via a switch like depwarn, it can be turned complete off for "rapid application development" (that could even be the default setting). There is nothing "mandatory" about what I've been proposing for Julia. |
@lobingera So, you do understand that encapsulation is really, really needed. To me, always having to run Lint while I'm developing something, is a much bigger speed limit than simply having the compiler warn me immediately. |
I think, this could be done somewhat like this:
However, this isn't urgently needed. Right now I don't think very long running or critical systems are being written in Julia. I also feel that Julia is useful outside of scientific computing. That currently though is not its focus. This probably should be revisited at a later date once field overloading has been implemented as without it this can't be implemented as nicely. |
it certainly doesn't stop LLVM from iterating their API continuously. additionally, in many cases, they enforce the public/private distinction via public / private headers – i'm not sure how well that transfers to a language based on dynamic reflection instead of headers, however. |
Could this be done in a package? E.g. with a As mentioned |
@vtjnash No, this isn't a cure-all, but at least in my experience, having the option of enforcing at least some level of encapsulation is critical to building reliable systems. Since I also stated that the default could be to simply not even warn or give error messages (a la depwarn), it wouldn't effect absolutely anybody who didn't need this functionality. @hayd if it can be done with say @public and @Private macros, that would be just fine, I really don't care so much about the syntax, but rather the functionality I need to be able to deliver reliable systems that will still be working in 30 years time. I still don't have my head wrapped around how to deal with Julia meta-programming yet, so I have no idea what is possible. @Mike43110 From conversations I had at JuliaCon, I think there are actually a number of people who would welcome anything that can be done to help writing maintainable, reliable, large applications in Julia. We (myself and the Belgian company I'm working for) are definitely interested in using Julia already for critical systems (which is why I take these issues so seriously). |
@hayd As @tkelman noted above (in the julia-users thread), Python's unenforced _ convention really is not enough. |
You also neglected to quote my other point. Prototype implementation or bust. Not worth spilling bits talking about it. |
I responded to that in the julia-users group. |
@ScottPJones I don't know enough about macros to know if it would be possible. It would make for a good prototype if possible though. |
@ScottPJones: Please stop quoting things out of the context this is very misleading. I have made pretty clear that for mutable types it is common practice in julia that fields are private and that for immutables this is not entirely clear. +1 for documenting the common practice and working on better interface support Julia is already an excellent language for writing maintainable large scale applications. The type system including subtyping of abstract types helps a lot in this. |
For what little that my opinion matters, -1 to making information hiding a part of the core language. +1 for better documenting what we consider to be idiomatic Julia, perhaps even a manual page on "Writing Idiomatic Julia Code". I would also like to propose "Access Equality" to replace "Consenting Adults", putting myself firmly in the pro-equality camp. |
I don't see the point in manually adding getter methods for every field of every type and changing all other code to use them for those cases where the data structure is an integral part of the API, and there's no way to make non-breaking changes anyway. I imagine a grep of package code that uses sparse matrices would show that 90% guess to be overly optimistic. |
I agree with @tkelman. When you have a data storage type, why would you want to write getter/setters which are just I do have a thought though. Is this necessary if name aliasing is allowed in #1974? If you wanted to mimic a private field you could just make a getter/setter return an error. Read-only fields would then be fields with only a get method added. You could still access the raw fields from For methods, modules already exist and |
@Mike43110 While, I'm fine with the public API of a module being defined by what it exports, I disagree with |
I agree that there are definitely times where the fields really are integral to the API and it seems like extra boilerplate to add accessor methods. I've always liked the opening to python's PEP8 which makes it explicit that the style guidelines are for encouraging default behavior and consistency, but not to be followed at the expense of clarity and good design. So far it seems like @tkelman's sparse matrix example is the most concrete counter-example. Can you point me/us to some of the code that exemplifies where accessing the fields is the better API? I think it would be great to have some more examples of when the "methods-over-fields" rule should be broken. |
Maybe that 90% number was reasonably accurate after all, since most quick searches for uses of the |
Where exactly is the issue? Don't you get The |
The issue is adding getter functions seems like a pointless exercise if they'll only ever be used for a single type. |
You may call it pointless but its common practice to decouple the interface from the implementation. The Image implementation shows that there are people that care for this distinction. But this is all a little subjective. One can also have in C++/Java public member variables. Its simply discouraged to do so. One could follow the Python/C# property business in order to have clean public properties. I am just not sure if its worth the complexity. |
My argument is it's not always necessary and it doesn't always buy you anything except polluting your namespace. You aren't really decoupling the interface from the implementation if the getters are all trivial - you've just moved any potential renaming breakage from the field name to the getter name. |
We don't have to argue about this point. It is very subjective and I am not a fan of enforcing anything in that direction. The suggestion that fields are private is for people very used to OO. In Java/C# it is absolutely standard to program against interfaces and these don't expose fields. (But again, the sparse matrix type is tricky because IMHO rowval and colptr are not really public because you can can render the object into an inconsistent state by direct access.) |
If it were impossible to do anything risky, we'd end up in a situation like Matlab where you have to jump through hoops like writing a mex file to actually touch the data structures you sometimes need to work with. I'm less convinced about safety and privacy on a language level as the discussion goes on. I just don't think the large-system, strong static safety guarantees design space is something that Julia will ever be perfectly suited for. To do that right it needs to be a design consideration from the very start, and it leads you to something that looks a lot like Ada or Rust. |
We should probably recommend avoiding direct field access and using accessor functions in general, but still consider it OK for some types to define an official fields API and tell users to use them directly. Indeed, for most types you shouldn't play with the internal representation, but for some, like sparse matrices, the code sometimes needs to be tightly related with the representation to be efficient. There would be little benefit in making it use accessors, as it only makes sense when applied to this particular representation of sparse matrices. But I still think it's worth recommending avoiding direct field access in most cases, i.e. "in absence of strong reasons against it, provide users with accessors; only require them to directly access fields for operations that are necessarily dependent on the internal representation of the object". |
With |
@KristofferC: Julia does not allow field overloading so this is just speculation. Properties are what seem to block #1974 because it will mix |
If this is so clear then this issue and #12083 are obsolete and can be closed. |
I don't think that dot operator overloading resolves this entire issue. When I write code, I establish an interface (through documentation, and possibly aided by appropriate language features). That is my contract with the user. I want to make it as small as possible so that I am free to change the implementation afterwards. With dot operator overloading, it will be a lot safer to establish an interface that includes field access. But for my implementation, I should still be able to use fields that are private (in the sense that I am free to change their meaning or remove them), without jumping through hoops such as creating dummy |
In case it helps.... the following Discourse comment provides and example of how to create private properties for a type. |
close #12064 close #7561 Co-authored-by: Spencer Russell <[email protected]>
close JuliaLang#12064 close JuliaLang#7561 Co-authored-by: Spencer Russell <[email protected]>
close JuliaLang#12064 close JuliaLang#7561 Co-authored-by: Spencer Russell <[email protected]>
close JuliaLang#12064 close JuliaLang#7561 Co-authored-by: Spencer Russell <[email protected]>
It is not documented that fields of types are considered private (at least by some people), as @nalimilan mentioned over in julia-users. It's probably worth giving some guidelines in the documentation when fields are considered private. As that is probably not always true, for instance when using a type just to store stuff.
Also, using an leading underscore is sometimes used to denote privacy of methods or (extra?) privacy of fields. When should
_
be used vs just assume privacy of fields? When should methods use a_
?It is probably worthwhile to reach some sort of consensus about this and documenting it before going forward with field overloading (#1974 and PR #5848).
The text was updated successfully, but these errors were encountered: