3

I've been reading about data hiding and there seem to be slightly different definitions of it, so when trying to come up with a practical example, I'm not sure if I'm doing the right thing.

So far, I got that data hiding protects data from being accessible in an unexpected way. This makes me think of two different cases, but I'm not sure if these actually describe data hiding or I'm describing something else:

  1. Let's say I have a Gym class and a Member class. The Gym class will have a container of Member object called members. So if I'm using Python, maybe it will be a list of Member. But if I add members to my Gym by doing gym.members.append(new_member) then I'm revealing the actual implementation of my container. This could cause trouble if, for example, at some point I wish to stop using a list and start using a dictionary, since I'd have to find and replace all lines where I've appended members. So to avoid this, I'd rather create a method called addMember(self, member) where I can manage my implementation internally, within the Gym class.
  2. The other case is where I don't want an attribute value to be changed directly, because I need to do some checks before. To extend the first example, let's say the Member class has also active and a lastPayment attributes where active is a boolean set to True when gym membership is active and to False otherwise, and lastPayment is the date of the last payment made by the gym member. When the last payment was made more than a month ago, then membership is automatically set to active=False and then only when a new payment is made it's set back to True. This means that the active value shouldn't be directly changed by doing member.active=False. So in that case I'd protect this attribute by naming it as __active.

So these are two different cases (revealing actual implementation and preventing accidental changes) that I understand to represent data hiding, and I'm not sure if both are just two different examples of data hiding or I have some misconception and I'm describing something else.

  • 2
    Both examples are valid, although the second case (attribute depends on data external to the object) you should not keep the value in a variable but compute it on the fly. But that's a valid reason for data hiding by itself. – Hans-Martin Mosner Jul 18 at 5:11
4

Data or information hiding just refers to the practice of making your class variables inaccessible from other classes. In Java and many other languages you do that by declaring the variable as "private", in Python you prefix the variable with double underscore. So the examples that you've mentioned are both valid use cases for data hiding.

1

A technical definition may be less clarifying than the reason for applying it. Your number 2 is just another property/ability of data hiding, not so much a reason to apply it.

Data hiding is a form of encapsulation and de-coupling with the intent of minimizing impact when internal design will change later. Have clients talk to an interface rather than directly to the data in order to allow you to move things around internally with minimal impact throughout the system. So your number 1 example is more to the point.

1

Is this data hiding?

Yes, it is.

Although you don't sound sure about it yet, it seems like you have understood the concept. That is already the full, direct answer to your question.

A little more detail

You were worried about changing the implementation, and that is a valid concern. However, there is an even nastier surprise waiting there; imagine code like this:

temporary_list = gym.members

# temporary_list gets passed around, until, somewhere else entirely:
temporary_list.append(new_member)

Some random, arbitrary code was now able to add a new member to the Gym, bypassing each and every rule the class might have internally.

This maps well to the real world. If the gym hands out a list of members to somebody, obviously it will only be a copy, and not the "master list" used internally, to determine income, fitness station maintenance needs etc.

In general

The real world metaphor works well with the given example, but that's not always the case. The important part is that other code can not access the fields of an object*. Everything that happens to them happens exclusively on the class' terms.


*An object hides data and exposes functionality. However, you will probably also use a couple of DTOs (data transfer object) in your application. Although they also have "object" at the end of the name, they are the complete opposite: They expose their data and don't have any functionality. Obviously, there's no data hiding going on with these and that's OK (even though Java programmers like to put a bunch of getters and setters on these, which technically are methods).

1

I agree with Martin Maat's remark that understanding the underlying reasons behind these practices will help you make sense of it all. You see, it's not so much about data hiding, it's more about strategically hiding implementation details (which include the choice of data structures you use internally, but also the exact details of how you implement behaviors - i.e., what happens under the hood when you call something). This is what we mean by encapsulation.

Encapsulation is strategic in the following sense - based on your knowledge of the problem, you (as the programmer/designer) make a distinction between what's public vs what's hidden.

Any client code (code calling your class directly) will then be written only in terms of the public stuff. This is what's known as the public interface of the class, and it specifies things like the set of public methods, their parameters and return types, what these methods mean and do in a general sense (as "seen" by the client code).

The private, encapsulated aspects of your class involve the details of how it all works inside the class - the data structures, the code that makes it all happen, if the class itself is doing all the work, or if it calls into other objects, etc.

The idea is that, since client code is written against the public interface, you can change the private implementation details independently (such as the algorithms used, the way you store state, your choice of data structures, if you call other classes/objects or not, etc), as long as the externally visible behavior remains in accordance to the public interface as you defined it (i.e. for client code, different implementations look the same).

So in that sense, the public interface is an abstraction: it defines how client code interacts with the class and what those interactions mean, but it doesn't specify the exact details of how it is all implemented (sometimes we say it defines a contract between the two). This in turn makes client code independent of those details, enabling you to change implementations without having to deal with cascading effects on the callers (and, possibly, callers of the callers, and so on).

If you look at things in this light - both of your examples have to do with encapsulation, but there's a subtle difference.

In (1.), what you made public (the part of the contract) is the fact that client code can add members, but you made private the actual data structure that stores them internally (as well as any code involved in that process), signalling to the callers that they should not make any assumptions about that (i.e. should not write code in a way that relies on the fact that in the current implementation a list is used).

In (2.), the contract of this class involves the behavior you've described. Note that this kind of thing is (in general) not something that can be understood by just examining the set of public methods/properties - one has to examine the class documentation as well. That's what we refer to when we talk about the meaning or the semantics of methods - the contract can involve more than can be expressed through code. So, in this case, any client code can expect that any implementation of your class will adhere to this behavior. Which means that client code can be written in a way that relies on this fact. Therefore, the fact that you are doing these checks to ensure this behavior, doesn't in itself constitute encapsulation, because if the class didn't behave like that, it would be broken - it wouldn't do what it is supposed to do (it would have a bug). That's the subtle difference that I mentioned. What is encapsulated here is the way you go about performing this check internally, how these attributes are actually stored ('cause you could do it in different ways), etc.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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