6

While I've never used a language that had built-in variable privacy, a book I'm reading by Douglas Crockford explains a way to create privacy in JavaScript, however it doesn't make sense to me so. The term "private" isn't something I think of as even being possible in a programming environment, since everyone working on the code can potentially change any mutable object or method right?

So the two things that don't make sense to me are

  • how privacy is helpful
  • how privacy is defined - fundamentally one developer can't keep something in source code absolutely private ("untouchable", as I understand it) from another developer, so where does one consider the variable "private"? When it's hard to reach?

Can someone explain this, possibly with a "real-world" example?

2
  • 9
    ...since everyone working on the code can potentially change any mutable object or method right? -- Not if you've encapsulated it in a method or class. It's only changeable within that method or class. See? Commented Sep 22, 2015 at 15:47
  • 1
    Scope is private in JS - thank god for it. You really did not want to use a language that has only global variables.
    – Bergi
    Commented Sep 22, 2015 at 21:35

6 Answers 6

37

Within software development, privacy (of software entities) is usually defined as restricting access to that variable/function/method. If a variable is private, then only functions or methods that belong to the same class or module are allowed/supposed to access that variable.

As you see, privacy here is completely unrelated to which developer is writing the code, but rather is is about which parts of the code have access to which other parts of the code.

The advantage of private variables or functions is that, by restricting which parts of the code have access, you can more easily reason about how the variable gets used and who will be affected if you change it.

7
  • 1
    All the other answers gave great detailed examples or explanations, I +1'ed everyone, but this is the answer that made it click.
    – J.Todd
    Commented Sep 22, 2015 at 16:16
  • 1
    I wish I could star this answer Commented Sep 22, 2015 at 18:31
  • 1
    It's worth noting that if your only methods are getters and setters, the advantages of private methods aren't near as apparent.
    – corsiKa
    Commented Sep 22, 2015 at 18:32
  • 1
    @corsiKa Going by the definition from the tag wiki, setters are used to control changes to a variable. So they most certainly can check and make sure you aren't making an invalid change and still accurately be called a setter.
    – 8bittree
    Commented Sep 22, 2015 at 20:04
  • 2
    @corsiKa - on the contrary, I'd say that a setter which does nothing except this.x = x isn't a setter, it's junk code. To be a proper setter, it would need to do something more than that. Commented Sep 22, 2015 at 21:28
15

Sure, a developer with access to the source code could start manipulating whatever they want. And in the process make something very fragile and unmaintainable.

By making as much private as possible, and respecting that, and only exposing well defined interfaces, you can make it simple to change things behind the scene to, for example, fix bugs or improve performance. If other code is messing around with variables, then changes are quite difficult, because they will cause that other code to break.

I'm unsure exactly how Javascript handles privacy, but in languages like Java and C++, there is some compiler support for enforcing privacy.

Consider a class representing an IP address:

public class IpAddress {

  public string ipAddress;

}

Right now, anyone can put whatever they want into ipAddress (it's a public field).

IpAddress ia = new IpAddress();
ia.ipAddress = "weeeee!";

Last I checked, weeeee! was not a valid IP address. But, by making it private, we can make sure invalid addresses are thrown out. Of, course, we'll still need a way of accessing it and updating it. So we make public methods:

public class IpAddress {

  private string ipAddress;

  public string toString() {
    return ipAddress;
  }

  public boolean setipAddress(string newIp) {

    if (isValid(newIp)) {
      ipAddress = newIp;

      return true;

    } else {
      return false;
    }
  }

}

Note that now we still have access to the IP address's value, and we can update it, but now we can be sure that when it is updated, the new value is a valid value, instead of something like weeeee!.

ia.ipAddress = "this won't compile";
ia.setipAddress("This won't update the address");
ia.setipAddress("192.168.0.1"); // works

Similarly, what if we decide that a string is a poor way of storing an IP address? Maybe a quartet of ints would be better. Before, when the ipAddress field was public, any code that used it, either to simply view it, or to change it, would break if we tried to change our storage scheme. But since we're using public methods for access instead of directly accessing the field, we can do this without breaking anything:

public class IpAddress {

  private int part1;
  private int part2;
  private int part3;
  private int part4;

  public string toString() {
    return "" + part1 "." + part2 + "." + part3 + "." + part4;
  }

  public boolean setipAddress(string newIp) {

    if (isValid(newIp)) {
      part1 = extractOct(newIp,1);
      part2 = extractOct(newIp,2);
      part3 = extractOct(newIp,3);
      part4 = extractOct(newIp,4);

      return true;

    } else {
      return false;
    }
  }

}

From the point of view of anyone using this class, it looks like this whether storing the IP address as a string or four ints:

public class IpAddress {

  public string toString()

  public boolean setIpAddress(string newIp)

}

and they don't need to know, or care that things changed behind the scenes.*

*In general. Some rare cases might care. E.g. realtime systems can be sensitive to performance changes, whether faster or slower.

9

Imagine that you're writing a javascript library, and you have defined a variable size that you store some size in. Since you don't encapsulate it, it goes into the global namespace.

Now someone comes along and assigns a value to size, not knowing that you've already defined it. Oh, dear. He just broke your library. And when you assign to size again, you break his code.

Now drink a toast to encapsulation.

2
  • I'm not sure that I understand moving something out of the global scope is the same as variable privacy. In JavaScript, Crockford creates privacy by using a closure. It seems to me the concept of defining variables outside the global namespace is something different than the privacy I'm reading about.
    – J.Todd
    Commented Sep 22, 2015 at 16:04
  • 3
    Everything in Javascript is in the global namespace unless you encapsulate it with a method. Commented Sep 22, 2015 at 16:14
2

It's important not to conflate two different things. You can't guarantee that nobody will change the source of your class, and you can't guarantee that it will still work as intended if somebody changes it. But what you can do is make it a lot easier for you to write code which works as expected right now, under all possible use cases.

For example, let's say you want to create a Fraction. It needs some functionality. Let's say it needs to be able to check for equality with another fraction. (Realistically it'd probably need to to a lot more, but let's keep it simple). We also want a rule: a fraction can always be reduced (2/4 = 1/2).

Let's try (I'm going to use C#-ish syntax rather than javascript but it should be readable enough):

public class Fraction
{
    public int Numerator;
    public int Denominator;

    public Fraction(int numerator, int denominator)
    {
        Numerator = numerator;
        Denominator = denominator;
        Reduce();
    }

    public void Reduce()
    {
        //Some implementation here to reduce this fraction
    }

    public bool Equals(Fraction other)
    {
        return Numerator == other.Numerator && Denominator == other.Denominator;
    }
}

Does this work? Well, no. What if somebody does this:

var aHalf = new Fraction(1,2);
var anotherHalf = new Fraction(2,4);
var same = aHalf.Equals(anotherHalf);  // This is true

anotherHalf.Numerator = 2;
anotherHalf.Denominator = 4;
same = aHalf.Equals(anotherHalf);  // This is false!

Maybe you might try to put a call to Reduce() inside Equals. But then what if you do this:

var aHalf = new Fraction(1,2);
var anotherHalf = new Fraction(2,4);
anotherHalf.Denominator = 2;
anotherHalf.Equals(aHalf);

anotherHalf.Numerator = 1;
var same = anotherHalf.Equals(aHalf); // This is false!

Because of the unexpected modification inside Equals, this code that looks like it should result in anotherHalf being 1/2, it's actually 1/1. Even more expected, if you'd done aHalf.Equals(anotherHalf), you'd have the opposite result.

What a confusing and complicated situation we've created for ourselves! And why? If you look back, the only functionality we decided Fraction needs is to expose Equals. So why did we also expose Numerator and Denominator and make it so hard to correctly implement the behaviour we actually need? All you need to do is make those private and our initial implementation works with no further issue.

1

Suppose that you're modeling a person, and as part of that you want to track the person's age. You might use an integer to represent the person's age. Would you want client code to be able to change the age of a person to a negative value?

In this example, making age something that is private, and providing public functions that operate on that value let you make certain guarantees about the variable's value.

Generally, private variables let you decouple client code from the solution representation, so that the representation can change without forcing the client to change.

1

As far as I understand it, 'encapsulation' is primarily about protecting the internal state of the system that you're developing.

Say you're developing a class with a few fields and methods:

class Arithmetic
{
    private int j;
    private int k;

    public Arithmetic(int j, int k)
    {
        this.j = j;
        this.k = k;
    }

    public int returnProduct()
    {
        return this.j * this.k;
    }

    public int returnSum()
    {
        return this.j + this.k
    }
}

In this example the only entry-point to change state within the class is through the constructor. So when you create an object of type Arithmetic you know beyond a shadow of a doubt what j and k are when you go to call returnProduct and returnSum.

Now let's look at it again but with a setter on one of the variables:

class Arithmetic
{
    private int j;
    private int k;

    public Arithmetic(int j, int k)
    {
        this.j = j;
        this.k = k;
    }

    public setj(int j)
    {
        this.j = j;
    }

    public int returnProduct()
    {
        return this.j * this.k;
    }

    public int returnSum()
    {
        return this.j + this.k
    }
}

Now if somebody instantiates an object of type Arithmetic, and then someone later takes that same object and updates one of it's fields with the setter, the object may return unexpected behavior.

So to generalize the purpose of privatization or 'encapsulation' (one of the three pillars of OO programming), in the first example what we're doing is minimizing a programmer's ability to mutate the state of the object.

The more we code in that style the more certain we are of the state of our system at any given time, and the less error prone our code will be.

So the general rule of thumb is this:

When you're coding only allow a programmer or user the minimum amount of visibility into the system that still allows them to either use the system or continue developing the system.

Not the answer you're looking for? Browse other questions tagged or ask your own question.