While I understand the value of implementation/interface distinction, I fail to see why most OO systems issue errors on access to private members.
I indeed wouldn't want to access private members in my main program.
But I would like to have that access for tests and debugging.
Is there any good reason whatsoever to issue errors and not warnings? The way I see it, I am forced to either write code I can test, but that doesn't utilize language support for interfaces, or use the language support, but have difficulty in testing.
EDIT
For those who suggested using public interfaces. You can, but it's less convinent.
On a conceptual level I find privacy that doesn't care about who or when quite crude.
Friend classes seem like a reasonable solutution. Another might be an 'all public' compiler switch.
The way I see it, I am forced to either write code I can test, but that doesn't utilize language support for interfaces, or use the language support, but have difficulty in testing.
Why do you need to access private variables and functions? Either they are called (however indirectly) by public functions at some point, or they are just inaccessible pieces of code that shouldn't be there at all because there is no way to invoke them. Think about it, if the private method is completely impossible to invoke from outside the class in any way at all, is it ever going to be run?
If you really want to test a private method anyway, you can pull it into its own class. Plus, if its so complex that it really needs to best tested individually, there's a chance that it deserves to have its a chance in the first place. The other option is to just make it public whenever you need/want to test it, but not actually change the 'real' code (leaving it private). As others have said, some languages also have features that help you test these methods by exposing them slightly more, such as friend in C++, internal in C#, and package-private in Java. Occasionally the IDE's themselves even help out.
Is there any good reason whatsoever to issue errors and not warnings?
One big reason is not so you can't call them, its so other people can't call them. Picture this, you're writing a library that's going to be used by a substantial number of clients. You've marked everything they shouldn't need to call private, and all the functionality they do need is public. Programmers go ahead and start using your library, write a bunch of code with it, and produce happy customers both out of themselves and their own clients.
A few months later, you decide to spice up your massively successful library, and find that you need to do a bit of refactoring. Hence, you [rename, add/remove a parameter from, delete] some of your private methods, but are careful to keep all of your public method's interfaces exactly the same to make upgrading a seamless process. BUT in this universe, compilers only issue warnings and not errors when you access a private variable, and several of your client programmers wrote code that calls those private methods. Now, when they try to upgrade to your new version of your library, they get a bunch of real errors because they can't call those private methods anymore. Now they either have to spend time finding out what went wrong with the code and rewrite potentially large parts of it that they don't remember anything about (did I mention that this is two years in the future?). Hence, they have to completely relearn how to use your library and rewrite their client code, which is far from fun for anybody. Now they're rather displeased that you were so inconsiderate as to literally break all of their code with your upgrade and make their lives far more difficult.
Guess what, when they were fixing the code, they researched and called your new private methods, so if you ever decide to change their interface when you issue an upgrade, the whole cycle starts over again. What was slightly more convenient for you just got you a bunch of unhappy customers.
Wait, weren't they idiots for calling my private methods? Why didn't they look at the warnings? This is their fault, not mine!
Well, yes, it is their fault and they could have prevented the problem by taking care to note those warnings. But not everybody is a code-quality fanatic who wants to fix and understand warnings, and a substantial amount of people just ignore them. The thing is, you could have prevented the whole thing yourself if compilers issued errors for trying to access private variables and methods instead of warnings, because otherwise the private keyword might as well not exist at all. You may have lost a little time because those methods are harder to test, but you have gained the power to keep less intelligent people from misusing your code and blaming you for any problems it causes them down the road.
One of my favorite tenets of software development (and product design in general) is that things should be easy to use correctly and hard or impossible to use incorrectly. True private members are the embodiment of this advice because they literally make your code impossible to use correctly.
[hypothetical retort:] Well, the people using my code should be smart enough to figure it out. All I'm asking them to due is just spend a little extra time to use the code correctly.
So you are consciously refusing to spend the time necessary to improve the quality of your code and make it easier to use? Then I don't want anything to do with what your code. Obviously your time is more important than that of your clients, so I'll take the 2.5 seconds it requires to close the web page for your project and click on the next Google result. There are a lot more private members of the libraries you use than you might think, and the glorious thing is that you don't have to spend even a millisecond of your time worrying about them because they're totally hidden from you and would only distract from the easier and better way of doing things that is provided in the public interface. If everything was public or wimpy-warning-issuing private, you'd have to sift through a greater amount of functions before you actually found what you wanted.
Whenever you type private before a member function, you have just given yourself the power to change it in any way you want at any point in the future because nobody can touch it but you. The second someone else tries to access it they will get a show-stopping error because the compiler has your back and won't let them do anything stupid with your code when you've already provided perfectly everything they need in a much more usable form in your public interface.
Yes, it will make it slightly harder to test in the now, but it has also ensured that you won't have to worry about it in the future when you refactor and made your code a lot easier for other people to use. Go ahead and make it public temporarily (I kind of like your 'all-public compiler switch idea :), but don't forget to switch it back when you're done you and your clients can all have the joy working with simpler and more adaptable code. :D
The obvious reason would be that all too many people seem to ignore many (all?) warnings. In some languages (e.g., Python) it's pretty much as you've said -- something being "private" is basically advice against outside code using it directly, but the compiler doesn't enforce that.
As for how much sense that makes, I suspect it varies between languages -- in something like C++, the attitude toward them ("protect against Murphy, not Machiavelli") could be seen as justification for its being a warning instead of an error.
I think it's safe to say that in Ada, that would receive a much cooler reception, to say the least (and that's not to say that I think it would be received warmly by C++ programmers either, just that they might not hate the idea quite as much as most Ada programmers would).
On the other hand, I have to wonder about the design of a class that can't be tested (at least reasonably well) via its external interface. On the rare (should be rare, anyway) occasion that you can't, I think making the test class a friend (in C++ parlance, though many others have similar concepts) would be fairly easy to justify.
There are several advantages to having complete encapsulation:
Security. Strongly-typed OOP languages with strong encapsulation can have certain guarantees about the security of the data in the program. The Java language was designed with safety and security in mind, so certain library classes (for example, String or SecurityManager) cannot have their fields accessed. This prevents malicious code from doing Bad Things to these objects, and allows code to assume the objects are safe.
Maintainability. One of the major reasons to keep private fields and methods private is to allow the implementation to change seamlessly; as long as no updates are made to the public interface, code using the updated class can work with no changes. If you allow access to private fields and then change the implementation, you risk breaking an unbounded amount of code.
Stability/Verifiability/Testability. Classes typically impose invariants on their fields - for example, an implementation of a dynamic array might require that a field tracking how much space is used actually correspond to the total number of elements. Allowing people to arbitrarily access private fields, even with a warning, makes it possible to break these invariants. Without the ability to count on the invariants, it becomes difficult or impossible to reason about the correctness of the code. Additionally, if you do break an invariant somewhere in the code, you would conceivably have to look at every piece of code in the program that has access to the object, since any of them might be accessing the private field. With strong encapsulation, these invariants can't break, and with semiencapsulation through friends or package-private mechanisms, the amount of code to look at is bounded.
As for your question about testing - many languages allow encapsulation to be broken in certain cases; C++ has friend, Java has package-private, etc., so that the class can say "normally you can't touch these, but exceptions can be made." You can then make your testing code a friend or in the same package as the main class in order to test it more thoroughly.
Hope this helps!
The way that I see it is that you need to forget about accessing anything in an object unless you have a way of doing that in that object's interface. I think a correct OO system ought to issue errors (and not warnings) if you are attempting to directly access implementation specific private members. I attended a good talk by Kevlin Henney on this subject recently and I found it very useful, a copy may be viewed here: http://www.infoq.com/presentations/It-Is-Possible-to-Do-OOP-in-Java (note that it is mainly about java but also includes comparisons to other OO systems)
For testing most time I find that most of the code under test is covered by public interface calls. It is only on rare occasions that I need to employ something like runtime reflection to get absolutely 100% coverage.
I was about to post, "Strong enforcement of encapsulation keeps your boss from stepping on your private members." until I realized how that might sound wrong, but on second thought It's
probably just about right.
Related
I don't really understand why it's generally good practice to make member variables and member functions private.
Is it for the sake of preventing people from screwing with things/more of an organizational tool?
Basically, yes, it's to prevent people from screwing with things.
Encapsulation (information hiding) is the term you're looking for.
By only publishing the bare minimum of information to the outside world, you're free to change the internals as much as you want.
For example, let's say you implement your phone book as an array of entries and don't hide that fact.
Someone then comes along and writes code which searches or manipulates your array without going through your "normal" interface. That means that, when you want to start using a linked list or some other more efficient data structure, their code will break, because it's used that information.
And that's your fault for publishing that information, not theirs for using it :-)
Classic examples are the setters and getters. You might think that you could just expose the temperature variable itself in a class so that a user could just do:
Location here = new Location();
int currTemp = here.temp;
But, what if you wanted to later have it actually web-scrape information from the Bureau of Meteorology whenever you asked for the temperature. If you'd encapsulated the information in the first place, the caller would just be doing:
int currTemp = here.getTemp();
and you could change the implementation of that method as much as you want. The only thing you have to preserve is the API (function name, arguments, return type and so on).
Interestingly, it's not just in code. Certain large companies will pepper their documentation with phrases like:
This technical information is for instructional purposes only and may change in future releases.
That allows them to deliver what the customer wants (the extra information) but doesn't lock them in to supporting it for all eternity.
The main reason is that you, the library developer, have insurance that nobody will be using parts of your code that you don't want to have to maintain.
Every public piece of your code can, and inevitably will get used by your customers. If you later discover that your design was actually terrible, and that version 2.0 should be written much better, then you realise that your paying customers actually want you to preserve all existing functionality, and you're locked in to maintaining backwards compatibility at the price of making better software.
By making as much of your code as possible private, you are unreservedly declaring that this code is nobody's business and that you can and will be able to rewrite it at any time.
It's to prevent people from screwing with things - but not from a security perspective.
Instead, it's intended to allow users of your class to only care about the public sections, leaving you (the author) free to modify the implementation (private) without worrying about breaking someone else's code.
For instance, most programming languages seem to store Strings as a char[] (an array of characters). If for some reason it was discovered that a linked list of nodes (each containing a single character) performed better, the internal implementation using the array could be switched, without (theoretically) breaking any code using the String class.
It's to present a clear code contract to anyone (you, someone else) who is using your object... separate "how to use it" from "how it works". This is known as Encapsulation.
On a side note, at least on .NET (probably on other platforms as well), it's not very hard for someone who really wants access to get to private portions of an object (in .NET, using reflection).
take the typical example of a counter. the thing the bodyguard at your night club is holding in his hands to make his punch harder and to count the people entering and leaving the club.
now the thing is defined like this:
public class Counter{
private int count = 0;
public void increment()
{
count++;
}
public void decrement()
{
count--;
}
}
As you can see, there are no setters/getters for count, because we don't want users (programmers) of this class, to be able to call myCounter.setCount(100), or even worse myCounter.Count -= 10; because that's not what this thing does, it goes up one for everyone entering and down for everyone leaving.
There is a scope for a lot of debate on this.
For example ... If a lot of .Net Framework was private, then this would prevent developers from screwing things up but at the same time it prevents devs from using the funcionality.
In my personal opinion, I would give preference to making methods public. But I would suggest to make use of the Facade pattern. In simple terms, you have a class that encapsulates complex functionality. For example, in the .net framework, the WebClient is a Facade that hides the complex http request/response logic.
Also ... Keep classes simple ... and you should have few public methods. That is a better abstraction than having large classes with lots of private methods
It is useful to know how an object s 'put together' have a look at this video on YouTube
http://www.youtube.com/watch?v=RcZAkBVNYTA&list=PL3FEE93A664B3B2E7&index=11&feature=plpp_video
I wanted to ask you all for you opinions on code smells in Objective C, specifically Cocoa Touch. I'm working on a fairly complex game, and about to start the Great December Refactoring.
A good number of my classes, the models in particular, are full of methods that deal with internal business logic; I'll be hiding these in a private category, in my war against massive header files. Those private categories contain a large number of declarations, and this makes me feel uneasy... almost like Objective-C's out to make me feel guilty about all of these methods.
The more I refactor (a good thing!), the more I have to maintain all this duplication (not so good). It just feels wrong.
In a language like Ruby, the community puts a LOT of emphasis on very short, clear, beautiful methods. My question is, for Objective C (Cocoa Touch specifically), how long are your methods, how big are your controllers, and how many methods per class do you all find becomes typical in your projects? Are there any particularly nice, beautiful examples of Classes made up of short methods in Objective C, or is that simply not an important part of the language's culture?
DISCLOSURE: I'm currently reading "The Little Schemer", which should explain my sadness, re: Objective C.
Beauty is subjective. For me, an Objective-C class is beautiful if it is readable (I know what it is supposed to do) and maintainable (I can see what parts are responsible for doing what). I also don't like to be thrown out of reading code by an unfamiliar idiom. Sort of like when you are reading a book and you read something that takes you out of the immersion and reminds you that you are reading.
You'll probably get lots of different, mutually exclusive advice, but here are my thoughts.
Nothing wrong with private methods being in a private category. That's what it is there for. If you don't like the declarations clogging up the file either use code folding in the IDE, or have your extensions as a category in a different file.
Group related methods together and mark them with #pragma mark statements
Whatever code layout you use, consistency is important. Take a few minutes and write your own guidelines (here are mine) so if you forget what you are supposed to be doing you have a reference.
The controller doesn't have to be the delegate and datasource you can always have other classes for these.
Use descriptive names for methods and properties. Yes, you may document them, but you can't see documentation when Xcode applies code completion, where well named methods and properties pay off. Also, code comments get stale if they aren't updated while the code itself changes.
Don't try and write clever code. You might think that it's better to chain a sequence of method calls on one line, but the compiler is better at optimising than you might think. It's okay to use temporary variables to hold values (mostly these are just pointers anyway, so relatively small) if it improves readability. Write code for humans to read.
DRY applies to Objective-C as much as other languages. Don't be worried about refactoring code into more methods. There is nothing wrong with having lots of methods as long as they are useful.
The very first thing I do even before implementing class or method is to ask: "How would I want to use this from the outside?"
I never ever, never begin by writing the internals of my classes and methods first. By starting of with an elegant public API the internals tend to become elegant for free, and if they don't then the ugliness is at least contained to a single method or class, and not allowed to pollute the rest of the code with it's smell.
There are many design patterns out there, two decades of coding have taught me that the only pattern that stand the test of time is: KISS. Keep It Simple Stupid.
Some general rules of thumb, for any language or environment:
Follow your gut feeling over any advice you have read or heard!
Bail out early!
If needed, verify inputs early and bail out fast! Less cleanup to do.
Never add something to your code that you do not use.
An option for "reverse" might feel like something nice to have down the road.
In that case add it down the road! Do not waste time adding complexity you do not need.
Method names should describe what is done, never how it is done.
Methods should be allowed to change their implementation without changing their name as long as the result is the same.
If you can not understand what a method does from it's name then change the name!
If the how part is complex enough, then use comments to describe your implementation.
Do not fear the singletons!
If your app only have one data model, then it is a singleton!
Passing around a single variable all over the place is just pretending it is something else but a singleton and adding complexity as bonus.
Plan for failures from the start.
Always use for doFoo:error instead of doFoo: from the start.
Create nice NSError instances with end user readable localized descriptions from the start.
It is a major pain to retrofit error handling/messages to a large existing app.
And there will always be errors if you have users and IO involved!
Cocoa/Objective-C is Object* Oriented, not **Class Oriented as most of the popular kids out there that claim to be OOP.
Do not introduce a dumb value class with only properties, a class without methods performing actual work could just as well be a struct.
Let your objects be intelligent! Why add a whole new FooParser class if a fooFromString: method on Foo is all you need?
In Cocoa what you can do is always more important than what you are.
Do not introduce a protocol if a target/action can do.
Do not verify that instances conforms to protocols, is a kind of class, that is up to the compiler.
My 2 cents:
Properties are usually better than old-style getter+setter. Even if you use #dynamic properties - declare them with #property, this is way more informative and shorter.
I personally don't simulate "private" methods for classes. Yes, I can write a category somewhere in the .m(m) file, but since Obj-C has no pure way to declare a private method - why should I invent one? Anyway, even if you really need something like that - declare a separate "MyClassPrivate.h" with a category and include it in the .m(m) files to avoid duplicating the declarations.
Binding. Binding for most Controller <-> UI relations, use transformers, formatters, just don't write methods to read/write controls values manually. It makes code look like something from MFC era.
C++, a lot of code look much better and shorter when written in C++. Since compiler understands C++ classes it's a good point for refactoring, especially when working will a low-level code.
I usually split big controllers. Something more than 500 lines of code is a good candidate for refactoring for me. For instance, I have a document window controller, since some version of the app it extends with image importing/exporting options. Controller grows up to 1.000 lines where 1/2 is the "image stuff". That's a "trigger" for me to make an ImageStuffController, instantiate it in the NIB and put all image-relative code in there.
All above make it easier for me to maintain my code. For a huge projects, where splitting the controllers and classes to keep 'em small results big number of files, I usually try to extract some code into a framework. For example, if a big part of the app is communicating with external web-services, there is usually a straight way to extract a MyWebServices.framework from the main app.
This is an open-ended question, but I would like to solicit some opinions from the SO community on Traits; do you think Traits in Squeak/Pharo are a good thing, or should you stay away from them and use composition and delegation instead? I ask because while I know how to use them (thanks to the Pharo book), I am not really sure how acceptable it is to use them or where it is OK to use them and where it isn't.
I do not like traits because they introduce strong dependencies into code. These dependencies can be obvious (a class that imports a trait, a trait that expects methods), but also very subtle (a trait that shadows super methods/instance variables). Furthermore there is no adequate tool support for traits.
In my experience delegation gives a much better and more reusable design in a dynamically typed object-oriented language like Smalltalk.
Things have their pros and cons. Lukas rightly mentions many of the cons:
Introduce strong dependencies into code.
no adequate tool support.
While the second may go away some day, the first will not.
The purpose of traits is to prevent code duplication that occurs, when two classes that don't share a superclass other than Object, share an instance method. Now, sometimes delegation can fix that, but oftentimes it cannot. So, the pro of traits is:
Reduced code duplication.
My verdict here is that the disadvantages overweigh. I think that, today and forever, code duplication is bound to occur. And when delegation won't do, I can even imagine that code duplication isn't all that harmful, as it often precedes the divergent evolution of the copied code snippets.
I think, the best thing to do, as of today, is to keep automated track of code duplication, and always monitor when one end changes while the other doesn't. I'm currently writing a tool that'll keep track of such links, even across repositories. I'll report on it in my blog when it's ready.
I understand the differences between them (at least in C#). I know the effects they have on the elements to which they are assigned. What I don't understand is why it is important to implement them - why not have everything Public?
The material I read on the subject usually goes on about how classes and methods shouldn't have unnecessary access to others, but I've yet to come across an example of why/how that would be a bad thing. It seems like a security thing, but I'm the programmer; I create the methods and define what they will (or will not) do. Why would I spend all the effort to write a function which tried to change a variable it shouldn't, or tried to read information in another class, if that would be bad?
I apologize if this is a dumb question. It's just something I ran into on the first articles I ever read on OOP, and I've never felt like it really clicked.
I'm the programmer is a correct assumption only if you're the only programmer.
In many cases, other programmers work with the first programmer's code. They use it in ways he didn't intend by fiddling with the values of fields they shouldn't, and they create a hack that works, but breaks when the producer of the original code changes it.
OOP is about creating libraries with well-defined contracts. If all your variables are public and accessible to others, then the "contract" theoretically includes every field in the object (and its sub-objects), so it becomes much harder to build a new, different implementation that still honors the original contract.
Also, the more "moving parts" of your object are exposed, the easier it is for a user of your class to manipulate it incorrectly.
You probably don't need this, but here's an example I consider amusing:
Say you sell a car with no hood over the engine compartment. Come nighttime, the driver turns on the lights. He gets to his destination, gets out of the car and then remembers he left the light on. He's too lazy to unlock the car's door, so he pulls the wire to the lights out from where it's attached to the battery. This works fine - the light is out. However, because he didn't use the intended mechanism, he finds himself with a problem next time he's driving in the dark.
Living in the USA (go ahead, downvote me!), he refuses to take responsibility for his incorrect use of the car's innards, and sues you, the manufacturer for creating a product that's unsafe to drive in the dark because the lights can't be reliably turned on after having been turned off.
This is why all cars have hoods over their engine compartments :)
A more serious example: You create a Fraction class, with a numerator and denominator field and a bunch of methods to manipulate fractions. Your constructor doesn't let its caller create a fraction with a 0 denominator, but since your fields are public, it's easy for a user to set the denominator of an existing (valid) fraction to 0, and hilarity ensues.
First, nothing in the language forces you to use access modifiers - you are free to make everything public in your class if you wish. However, there are some compelling reasons for using them. Here's my perspective.
Hiding the internals of how your class operates allows you to protect that class from unintended uses. While you may be the creator of the class, in many cases you will not be the only consumer - or even maintainer. Hiding internal state protects the class for people who may not understand its workings as well as you. Making everything public creates the temptation to "tweak" the internal state or internal behavior when the class isn't acting the way you may want - rather than actually correcting the public interface of internal implementation. This is the road to ruin.
Hiding internals helps to de-clutter the namespace, and allows tools like Intellisense to display only the relevant and meaningful methods/properties/fields. Don't discount tools like Intellisense - they are a powerful means for developers to quickly identify what they can do with your class.
Hiding internals allows you to structure an interface appropriate for the problem the class is solving. Exposing all of the internals (which often substantially outnumber the exposed interface) makes it hard to later understand what the class is trying to solve.
Hiding internals allows you to focus your testing on the appropriate portion - the public interface. When all methods/properties of a class are public, the number of permutations you must potentially test increases significantly - since any particular call path becomes possible.
Hiding internals helps you control (enforce) the call paths through your class. This makes it easier to ensure that your consumers understand what your class can be asked to do - and when. Typically, there are only a few paths through your code that are meaningful and useful. Allowing a consumer to take any path makes it more likely that they will not get meaningful results - and will interpret that as your code being buggy. Limiting how your consumers can use your class actually frees them to use it correctly.
Hiding the internal implementation frees you to change it with the knowledge that it will not adversely impact consumers of your class - so long as your public interface remains unchanged. If you decide to use a dictionary rather than a list internally - no one should care. But if you made all the internals of your class available, someone could write code that depends on the fact that your internally use a list. Imagine having to change all of the consumers when you want to change such choices about your implementation. The golden rule is: consumers of a class should not care how the class does what it does.
It is primarily a hiding and sharing thing. You may produce and use all your own code, but other people provide libraries, etc. to be used more widely.
Making things non-public allows you to explicitly define the external interface of your class. The non-public stuff is not part of the external interface, which means you can change anything you want internally without affecting anyone using the external interface,
You only want to expose the API and keep everything else hidden. Why?
Ok lets assume you want to make an awesome Matrix library so you make
class Matrix {
public Object[][] data //data your matrix storages
...
public Object[] getRow()
}
By default any other programmer that use your library will want to maximize the speed of his program by tapping into the underlying structure.
//Someone else's function
Object one() {data[0][0]}
Now, you discover that using list to emulate the matrix will increase performance so you change data from
Object[][] data => Object[] data
causes Object one() to break. In other words by changing your implementation you broke backward compatibility :-(
By encapsulating you divide internal implementation from external interface (achieved with a private modifier).
That way you can change implementation as much as possible without breaking backward compatibility :D Profit!!!
Of course if you are the only programmer that is ever going to modify or use that class you might as well as keep it public.
Note: There are other major benefits for encapsulating your stuff, this is just one of many. See Encapsulation for more details
I think the best reason for this is to provide layers of abstraction on your code.
As your application grows, you will need to have your objects interacting with other objects. Having publicly modifiable fields makes it harder to wrap your head around your entire application.
Limiting what you make public on your classes makes it easier to abstract your design so you can understand each layer of your code.
For some classes, it may seem ridiculous to have private members, with a bunch of methods that just set and get those values. The reason for it is that let's say you have a class where the members are public and directly accessible:
class A
{
public int i;
....
}
And now you go on using that in a bunch of code you wrote. Now after writing a bunch of code that directly accesses i and now you realize that i should have some constraints on it, like i should always be >= 0 and less than 100 (for argument's sake).
Now, you could go through all of your code where you used i and check for this constraint, but you could just add a public setI method that would do it for you:
class A
{
private int i;
public int I
{
get {return i;}
set
{
if (value >= 0 && value < 100)
i = value;
else
throw some exception...
}
}
}
This hides all of that error checking. While the example is trite, situations like these come up quite often.
It is not related to security at all.
Access modifers and scope are all about structure, layers, organization, and communication.
If you are the only programmer, it is probably fine until you have so much code even you can't remember. At that point, it's just like a team environment - the access modifiers and the structure of the code guide you to stay within the architecture.
I'm a student looking for resources which can help me further understand how to properly apply access modifiers to members/types as I code them.
I know (in C#) what restrictions access modifiers like private, public, protected, etc. put into place. When I code my own little projects I have a tendency to just make everything public. I'm certain this is an absolutely horrible practice as it just tosses encapsulation out the window. I just never know when it's correct to use something like internal vs. private.
Does anyone have any good resources to aid me in understanding the proper use of access modifiers?
This is an experience type question. Start from the level of least privilege and promote up as necessary.
In other words, make everything private. Until you discover that it needs to be promoted to protected or public. Over time you will get a feel for the intended and later discovered usages of your classes.
I simply make everything's access as restrictive as possible:
Private by default
Otherwise internal, if it's an API exposed to other classes within this assembly
Or, public if it's an API exposed outside the assembly
Or, protected if it's intended to be called only from subclasses.
Start putting everything private. If you feel the need, change the modifier accordingly, until you have the feeling to choose the right type.
To make things easier, try using TDD, or you might get into even more trouble when you get to write unit tests...
Any kind of tutorial or teaching material will give you the same guidance, namely the one that the other postings already gave you. So don't expect much useful information in this specific matter from "resources".
The primary resource that goes beyond that is code that other people have written. Take a large C# project (e.g. Mono, or SharpDevelop), and study how they specifically followed the principles that have been explained to you. Also, if you have a specific class to design, try to think of a similar class in the system libraries, and try to find out how it is implemented (either by looking at the Mono source, or by using the .NET reflector).
You should start by thinking about the interface of a class, that is the necessary and sufficient set of routines it needs to expose in order to achieve its purpose. Make that public. Everything else should be private.
I have a tendency to make everything protected that is not public. Leaving the freedom of my users to do whatever they want with my class. If their class breaks that would be their problem.
Every time you inherit from a class you need to know how it works even if oop is about hiding the implementation. You can hide the implementation, but you won't hide the documentation.