Encapsulation

Posted by RetroX on March 5, 2011, 5:21 p.m.

I just don't get it.

People treat the programmer that is using their code like an ordinary user. They treat you like you have no idea whatsoever about any kinds of programming concepts, and like you need everything to be spoon-fed to you through a list of implementation functions.

class point2d
{
  private:
    double x, y;

  public:
    double get_x() { return x; }
    double get_y() { return y; }
    
    void get_x(double val) { x = val; }
    void get_y(double val) { y = val; }
};

versus:

struct point2d
{
  double x, y;
};

The first completely ruins my ability to do useful things, such as pt.x += 1. Instead, I have to do pt.set_x(pt.get_x() + 1). Granted, you can still add operators and such to this if you're using C++ (not in Java) or add functions like add_x and add_y, but you have to then ask why the hell that you thought of this in the first place.

Even for things like strings, I don't really get it. I mean, yeah, it's kind of pointless to make an array class which stores a pointer and an integer for length and then just modify the pointer directly. But it's stupid to "hide" this from the user when the user clearly knows that it's there, and to provide get() and set() functions which essentially allow you to modify the variable directly.

I do understand if you're trying to only allow getting a value, but if it's just another programmer using it, why hide it? It's not like making the variables in a point class magically enable users to edit the points that are being used by the program. It's not like users would be able to access your database info if it's made public unless you're allowing them to execute PHP - in which case, you've already allowed the user to bypass anything.

I mean, in the programming concepts in my Java class, they use examples in things like bank accounts. They make a class called BankAccount and add withdraw(), deposit(), and a constructor. But the variable containing the money is private. The rationale? We don't want you editing the money the BankAccount directly!!!

But uh, it's already being done directly. If withdraw() and deposit() were functions that inputted PIN numbers and such to validate things or had limits, I'd be fine with that. But they're not. You're directly modifying stuff, and I don't see why you have to hide a number from me but let me edit it indirectly.

I mean, even if the implementation is confusing, there's no reason to hide it. Oftentimes, the implementation is essentially defined by member functions - for example, std::vector has size() and capacity(). This already tells me that somewhere, there is a stored size and a stored capacity. And, it stores a dynamically-sized array, which tells me that it contains a pointer to said array. I've already identified the vector implementation.

While the functions that are implemented may be changed, the data itself never changes. Why is it kept hidden? If I go messing into it and break the vector because of modified data, then that's my fault. But I don't see why you have to hide it from me.

I'm too lazy to write a conclusion, so, there you go.

Comments

PY 13 years, 1 month ago

It's a very useful abstraction. You want to keep private variables private to ensure modularity, if you have everything accessible only via getters and setters then you can swap out the exact implementation of the type without affecting existing code. It also means you can add, say, bounds checking or verification at a later date without having to modify large amounts of existing code.

It's basically there to ensure modularity. That's a very good thing, when you're using something you don't need to know the specifics of what it's doing, you just need to know what it's doing. Partially to reduce information overload, partially to reduce the chance of bugs (And make them easier to fix when they do show themselves), and partially so behavior can be added or modified very easily.

RetroX 13 years, 1 month ago

I kind of see what you're saying, but for things like bounds checking, for example, won't affect previous implementations. And I don't see what's wrong with adding functions to mess with the data in a friendly way and having everything use those implementations while still allowing the user to make their own with the existing data if they need to.

I guess that I just find it as a pointless feature to hide the data rather than just tell someone to not mess with it unless there's a good reason. Like protecting a database. But most of the cases that it's used in don't have that.

Josea 13 years, 1 month ago

PY summed up pretty much what I was about to say.

Also, I usually have as a rule of thumb that if I think something is silly or stupid, it's probably because I'm silly and stupid. Far more experienced scientists and engineers haven't worked through decades to create these concepts just because they wanted to screw us.

RetroX 13 years, 1 month ago

Well, I don't think that they're just screwing with us; I just thing that they're trying to overgeneralise a concept that's not in need of it. A lot of things that have been thought-out by experienced people aren't always the best for everything, despite being good in some cases.

PY 13 years, 1 month ago

because the user should never touch the private variables of a class. They're private for a reason, they all the very important process of abstraction to take place. In your example:

Your BankAccount class has two functions, withdraw and deposit. You have written a full banking application around these two functions that simply add and subtract from the private money variable.

Now, there's a bug - people are withdrawing more money than they have. If you're touching the variable directly, you now have to find everywhere in the code you can withdraw and add bounds checking. With the setter methods you can add it once and have done with it.

Your company is now looking overseas - your old system of simply subtracting won't do anymore, you need to be able to automatically convert the currency. If you're using the withdraw method, there's only one thing you have to add and it's invisible to the rest of the code.

It's slightly more effort to begin with, but it simplifies further development something fierce. And, as Josea said, the language standards were designed by people far more experienced than yourself.

RetroX 13 years, 1 month ago

Yes, and if you're letting the user directly withdraw and deposit without checking for a PIN, you might as well make the variable public, because you're already bankrupt.

What I meant to say about the implementation is that if you're just letting the user directly access it without any guards, just make it public. If, at any point in the future, you'd want to hide it, make it private. Like something like a point class, where data is always the same.

A BankAccount would likely be more like this:

struct Debt
{
  BankAccount& from;
  BankAccount& to;
  unsigned int amount;
  Debt(BankAccount& f, BankAccount& t, unsigned int amt) :
  from(f), to(t), amount(amt) { }
};

struct BankAccount
{
  private:
    string password;
    unsigned int moneyInUSCents;
    list<Debt> awaitingTransactions;

  public:
    void transfer(string pw, unsigned int amountInUSCents, BankAccount& account)
    {
      ...
    }

    void payDebt()
    {
      ...
    }

    bool checkPassword(string pw)
    {
      ...
    }
};

PY 13 years, 1 month ago

No, design your application properly from the start, even if you don't think you'll need it. Failure to do so will simply lead to headaches later.

RetroX 13 years, 1 month ago

Yes, and for things like points, you never will need it to be any different. You're just making it more of a headache by making things private.

Controlling bank accounts with OO is a terrible idea.

PY 13 years, 1 month ago

Yes, but it's also an example. I also don't know why you'd do it for a point struct, but that does not mean the underlying development structure is not a very sound one.

RetroX 13 years, 1 month ago

I don't know either, and if you take a look at Java, everything is encapsulated. Even points.

It's extremely useful in some cases, but the idea of encapsulating everything is stupid. It's only good when you're hiding things from the actual user, not the programmer. Lack of planning is always a bad idea, regardless, and if you don't plan ahead, then headaches will always show up.