44

Why shouldn't one leave all methods and attributes accessible from anywhere (i.e. public)?

Can you give me an example of a problem I can run into if I declared an attribute as public?

Marc Towler
  • 705
  • 11
  • 32
tirenweb
  • 30,963
  • 73
  • 183
  • 303
  • 2
    We can't provide a simple one-liner example of why encapsulation is good. [Read about it](http://en.wikipedia.org/wiki/Flow-based_programming#Object-oriented_programming), and decide for yourself. – user229044 Sep 12 '11 at 17:26
  • What can go wrong, WILL go wrong. Humans tend to think that all buttons are meant for pressing, even when the sign says "don't push button". Why do you hide your purse in the trunk when you want to leave it in the car? Because of the thief doesn't see it, they are not tempted to fiddle and break things they have no right to be touching. Hiding your purse decreases chances of theft. Hiding your methods equals "out of sight, out of mind". Having removed possibilities, Murphy's law CANNOT strike you down at the worst possible moment. – Eric Leschinski Oct 10 '13 at 18:36

12 Answers12

145

Think of McDonald's as an object. There's a well known public method to order a BigMac.

Internally there's going to be a few zillion other calls to actually GET the materials for making that Bigmac. They don't want you to know how their supply chain works, so all you get is the public Gimme_a_BigMac() call, and would never ever allow you to get access to the Slaughter_a_cow() or Buy_potatoes_for_fries() methods.

For your own code, that no one will ever see, go ahead and leave everything public. But if you're doing a library for others to reuse, then you go and protect the internal details. That leaves McDonald's free to switch to having Scotty beam over a patty rather than having to call up a Trucking company to deliver the meat by land. The end-user never knows the difference - they just get their BigMac. But internally everything could fundamentally change.

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
Marc B
  • 356,200
  • 43
  • 426
  • 500
  • 4
    As ridiculous as the example is, it's actually a good description, especially later on with the library description. Creating APIs, I often find it invaluable to be able to keep the same external controls (`public` methods), while completely overhauling internal controls (`private` or `protected` methods) to improve site performance while offering the same relied-upon responses. – stslavik Sep 12 '11 at 17:33
  • 52
    I don't think this is a ridiculous analogy at all. After all, McDonald's _is_ an object and `Gimme_a_BigMac()` and `Slaughter_a_cow()` are indeed methods. :) Furthermore, if McDonald's decides to use their own potato farm, the internal, private/protected method `Buy_potatoes_for_fries()` would change to `Pick_potatoes_for_fries()` and the public wouldn't even notice the change. +1 for a great analogy. – Herbert Sep 12 '11 at 17:41
  • 44
    Should -1 for implying McDonald's burgers are made from actual meat. – Anthony Pegram Sep 12 '11 at 19:52
  • 4
    @anthony pegram: Amusingly, there's 2 RottenRonnie's undergoing renovations here, and both are getting their sewer lines upgraded. I'm not sure if that's for increased disposal.... or increased raw material intake :p – Marc B Sep 12 '11 at 19:57
  • 2
    Excellent analogy, would add that it still matters if no one else will ever see your code, because you will see your code. It lets you separate your application into components which can be changed without breaking the rest of your application. It's about stopping yourself calling a method you didn't mean to call outside of a certain context. – ForbesLindesay Sep 19 '11 at 10:22
45

Why shouldn't one leave all methods and attributes accessible from anywhere (i.e. public)?

Because that is far too expensive.

Every public method that I make has to be carefully designed and then approved by a team of architects, it has to be implemented to be robust in the face of arbitrarily hostile or buggy callers, it has to be fully tested, all problems found during testing have to have regression suites added, the method has to be documented, the documentation has to be translated into at least twelve different languages.

The biggest cost of all though is: the method has to be maintained, unchanged, forever and ever, amen. If I decide in the next version that I didn't like what that method did, I can't change it because customers now rely on it. Breaking backwards compatibility of a public method imposes costs on users and I am loathe to do that. Living with a bad design or implementation of a public method imposes high costs on the designers, testers and implementers of the next version.

A public method can easily cost thousands or even tens of thousands of dollars. Make a hundred of them in a class and that's a million dollar class right there.

Private methods have none of those costs. Spend shareholder money wisely; make everything private that you possibly can.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 1
    And then you have people using System.Reflection. :) – Roman Royter Sep 12 '11 at 20:09
  • 3
    @Roman R.: Those people are using the fact that their code is fully trusted to expose internal implementation details of other classes. You take responsibility for things breaking horribly if you are going to explicitly use your privileges to override the safety system. – Eric Lippert Sep 12 '11 at 20:36
  • @Erik Lippert, agreed. I could only wish that these people realize the possible consequences to their actions. Unfortunately, many do not. – Roman Royter Sep 12 '11 at 21:18
  • 2
    +1 I'd really like to be payed "thousands or even tens of thousands of dollars" for every method I don't make public :P – NikiC Sep 13 '11 at 17:27
  • 3
    NikiC: You're not paid those dollars; you save those dollars. In this dream world, you'd have made a negative salary if you made everything public! – configurator Sep 13 '11 at 18:40
12

Think of visibility scopes as inner circles of trust.

Take yourself as an example, and think about what activities are public and what are private or protected. There are number of things that you are not delegating for anybody to do on your behalf. There are some that are fine others to trigger and there are some with limited access.

Similarly, in programming, scopes give you tools for creating different circles of trust. Additionally, making things private/protected, give you more control on what's happening. For example, you can allow 3rd-party plugins that can extend some of your code, while they can be limited to the scope of how far they can go.

So, to generalize, scopes give you the extra level of security and keeps things more organized that they would be otherwise.

Amal Murali
  • 75,622
  • 18
  • 128
  • 150
jancha
  • 4,916
  • 1
  • 24
  • 39
10

Because that violates the concept of encapsulation, a key tenet of OOP.

Daniel A. White
  • 187,200
  • 47
  • 362
  • 445
  • Javascript supports encapsulation using closures. I believe you can use Smalltalk's messaging system to support private-ish methods. Python's just weird ;) Also, people sometimes use the `def _methodname` notation to denote private members. Even if it's not enforced at compile time, you can still use the idea of private members in your code. Even languages that support private members can be cajoled to call private code by using reflection, etc. – wprl Sep 13 '11 at 18:30
  • 1
    I don't know about smalltalk and python but I laugh when people say that JavaScript is OO. Maybe in opposite world! – Maxim Gershkovich Sep 18 '11 at 23:35
9

A risk you run, you say?

<?php

class Foo
{
    /**
     * @var SomeObject
     */
    public $bar;
}

Your code states that $bar should contain an object instanceof SomeObject. However, anyone using your code could do

$myFoo->bar = new SomeOtherObject();

... and any code relying on Foo::$bar being a SomeObject would break. With getters and setters and protected properties, you can enforce this expectation:

<?php

class Foo
{
    /**
     * @var SomeObject
     */
    protected $bar;

    public function setBar(SomeObject $bar)
    {
        $this->bar = $bar;
    }
}

Now you can be certain that any time Foo::$bar is set, it will be with an object instanceof SomeObject.

Problematic
  • 17,567
  • 10
  • 73
  • 85
4

By hiding implementation details, it is also preventing an object from getting into an inconsistent state.

Here is an contrived example of a stack (pseudo code).

public class Stack {

  public List stack = new List();
  public int currentStackPosition = 0;

  public String pop() {
    if (currentStackPosition-1 >= 0) {
      currentStackPosition--;
      return stack.remove(currentStackPosition + 1);
    } else {
      return null;
    }
  }

  public void push(String value) {
    currentStackPosition++;
    stack.add(value);
  }
}

If you make both variables private the implementation works fine. But if public you can easily break it by just setting an incorrect value for currentStackPosition or directly modifying the List.

If you only expose the functions you provide a reliable contract that others can use and trust. Exposing the implementation just make it a thing that might work of nobody messes with it.

OliverS
  • 1,251
  • 12
  • 17
2

Encapsulation is not needed in any language, but it's useful. Encapsulation is used to minimise the number of potential dependencies with the highest probability of change propagation also it helps preventing inconsistencies :

Simple example: Assume we made a Rectangle class that contained four variables - length, width, area, perimeter. Please note that area and perimeter are derived from length and width (normally I wouldn't make variables for them), so that changing length would change both area and perimeter.

If you did not use proper information hiding (encapsulation), then another program utilizing that Rectangle class could alter the length without altering the area, and you would have an inconsistent Rectangle. Without encapsulation, it would be possible to create a Rectangle with a length of 1 and a width of 3, and have an area of 32345.

Using encapsulation, we can create a function that, if a program wanted to change the length of the rectangle, that the object would appropriately update its area and perimeter without being inconsistent.

Encapsulation eliminates the possibilities for inconsistency, and shifts the responsibility of staying consistent onto the object itself rather than a program utilizing it.

However at the same time encapsulation is sometimes a bad idea, and motion planning and collision (in game programming) are areas where this is particularly likely to be the case.

the problem is that encapsulation is fantastic in places where it is needed, but it is terrible when applied in places where it isn’t needed like when there are global properties that need to be maintained by a group of encapsulation, Since OOP enforced encapsulation no matter what, you are stuck. For example, there are many properties of objects that are non-local, for example, any kind of global consistency. What tends to happen in OOP is that every object has to encode its view of the global consistency condition, and do its part to help maintain the right global properties. This can be fun if you really need the encapsulation, to allow alternative implementations. But if you don’t need it, you end up writing lots of very tricky code in multiple places that basically does the same thing. Everything seems encapsulated, but is in fact completely interdependent.

Mouna Cheikhna
  • 38,870
  • 10
  • 48
  • 69
  • Yes! I just have a global object that gets passed on to every class, otherwise I have to do stuff like this.parent.getChildByName("foo").score++ – apscience Sep 14 '11 at 03:57
2

Well, in fact you can have everything public and it doesn't break encapsulation when you state clearly, what is the contract, the correct way to use objects. Maybe not attributes, but methods are often more hidden than they have to be.

Remember, that it is not you, the API designer, that is breaking the encapsulation by making things public. It is the users of the class that can do so, by calling internal methods in their application. You can either slap their hands for trying to do so (i.e. declaring methods private), or pass the responsibility to them (e.g. by prefixing non-API methods with "_"). Do you really care whether someone breaks his code by using your library the other way you advice him to do? I don't.

Making almost everything private or final -- or leaving them without API documentation, on the other hand -- is a way of discouraging extendability and feedback in open source. Your code can be used in a ways you even didn't think of, which might not be the case when everything is locked (e.g. sealed-by-default methods in C#).

pwes
  • 2,040
  • 21
  • 30
1

To save you from yourself!

There's been some excellent answers above, but I wanted to add a bit. This is called principle of least privilege. With less privilege, less entities have authority to break things. Breaking things is bad.

If you follow the principle of least privilege, the principle of least knowledge (or Law of Demeter) and single responsibility principle aren't far behind. Since your class you wrote to download the latest football scores has followed this principle, and you have to poll it's data instead of it being dumped straight to your interface, you copy and paste the whole class into your next project, saving development time. Saving development time is good.

If you're lucky, you'll be coming back to this code in 6 months to fix a small bug, after you've made gigaquads of money from it. Future self will take prior self's name in vain for not following the above principles, and he will fall victim to a violation of the principle of least astonishment. That is, your bug is a parse error in the football score model, but since you didn't follow LOD and SRP, you're astonished at the fact that you're doing XML parsing inline with your output generation. There are much better things in life to be astonished by than the horrificness of your own code. Trust me, I know.

Since you followed all the principles and documented your code, you work two hours every Thursday afternoon on maintenance programming, and the rest of the time surfing.

wjl
  • 7,143
  • 1
  • 30
  • 49
1

The only problem you can run into is that people will see you as "uncool" if you don't use Private or Protected or Abstract Static Final Interface or whatever. This stuff is like designer clothes or Apple gadgets - people buy them not because they need to, but just to keep up with others.

Yes, encapsulation is an important theoretical concept, but in the practice "private" and friends rarely make sense. They might make some sense in Java or C#, but in a scripting language like PHP using "private" or "protected" is sheer stupid, because encapsulation is invented to be checked by a compiler, which doesn't exist in PHP. More details.

See also this excellent response and @troelskn and @mario comments over here

Community
  • 1
  • 1
user187291
  • 53,363
  • 19
  • 95
  • 127
1

The visibility is just something that you can use for your own good, to help you not break your own code. And if you use it right, you will help others (who are using your code) that don't break their own code (by not using your code right).

The simplest, widely known example, in my opinion is the Singleton pattern. It's a pattern, because it's a common problem. (Definition of pattern from Wikipedia:

is a formal way of documenting a solution to a design problem

Definition of the Singleton pattern in Wikipedia:

In software engineering, the singleton pattern is a design pattern used to implement the mathematical concept of a singleton, by restricting the instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system.

http://en.wikipedia.org/wiki/Singleton_pattern

The implementation of the pattern uses a private constructor. If you don't make the constructor private, anyone could mistakenly create a new instance, and break the whole point of having only one instance.

Iravanchi
  • 5,139
  • 9
  • 40
  • 56
1

You may think that the previous answers are "theoretical", if you use public properties in Doctrine2 Entities, you break lazy loading.

Francesco
  • 454
  • 1
  • 3
  • 12