Let me start by answering your questions:
Data representation is the storage type of the data and what meaning the possible values of that data have. For example, a Boolean value may be stored as a single bit, where the bit being 1
means truth and 0
means falsehood.
Data representation is exposed by making something with a type (variable, class member) visible to outside.
Information hiding means using language constructs to prevent the inner workings of a module from being visible to other code. "Inner workings" can mean anything that makes the module tick, such as the fact that a piece of data exists, its representation and how values are determined (stored, calculated or both).
Here's a practical example that should answer the question I think you're really asking based on some of your comments:
Let's say you're developing an application that needs a class to represent a date. You come up with something that makes no effort to hide information, where all members are public and there are no methods to manipulate them:
class Date { // Irrelevant parts left out for brevity
...
public int month; // Month of year, 1 = January
...
}
Your team goes on to write many thousands of lines of code that use Date
, all of which assume that the first month of the year, January, is represented by the value 1
and reach directly into the structure to access it:
Date foo;
...
foo.month = 1; // January
...
One day, someone discovers that a critical function would be much more efficient if it's given zero-based months (0
for January, 1
for February, etc.) instead of having to do the arithmetic to produce one every time it reads or writes the month
member of a Date
. Management decides the business case for making the change is a good one and says to make it happen.
The critical function is re-written to use zero-based months, which means that every other line of code in the application that deals with months is now broken because it doesn't use the correct values. It may compile because the value is still an integer, but it's no longer using the correct values. What was January (1
) is now February, and what was December (12
) is no longer a valid value because zero-based months end at 11
.
(This example is a bit contrived, because good practice would dictate having the class define constants for well-known values like Date.MONTH_JANUARY
, but bear with me. The principle still applies.)
Correcting the broken code gives you a lot to do:
- Identify every use of a
Date
in the entire application
- Check each of those uses to determine whether or not it makes any assumptions about the value of the
month
member
- Change those that do to use the new rules
- Re-test all of it
- Get on your knees and pray you didn't miss anything
The costs of this effort can be huge in terms of labor to make and test the changes and risk to the business if a mistake (or the correction of one) would result in lost revenue.
Had Date
been developed using information hiding in the first place, there would be ways to manipulate the month that are independent of how it's stored:
class Date {
...
private int month; // Month of year, 1 = January
...
// These methods operate on the month as a 1-based value and
// are the ones all of the existing code uses.
void set_month(int new_month) { month = new_month; }
int get_month() { return month; }
}
Making the change to zero-based storage makes your to-do list a lot more pleasant and a lot less risky:
- Re-comment the
month
member to indicate that it's now zero-based
- Change
set_month()
and get_month()
to do the arithmetic to convert to/from one-based to zero-based on the way in/out
- Test the changed methods for correctness
- Add and test methods to do zero-based operations on
month
so the new version of the critical function can use them
The class now looks like this:
class Date {
...
private int month; // Month of year, 0 = January
...
// These methods operate on the month as a 1-based value and
// are the ones all of the existing code uses.
void set_month(int new_month) { month = new_month - 1; }
int get_month() { return month + 1; }
// New methods that operate on the month as a 0-based value
void set_month_zero(int new_month) { month = new_month; }
int get_month_zero() { return month; }
}
The key here is, again, that nothing outside the class knows anything about how the month is stored or even if it's stored at all. All they see is two methods called set_month()
and get_month()
that have to be used to store or retrieve the one-based value. As long as the new implementations of those methods can be proven to behave as they always did, there's no need to touch the thousands of lines of code that use them. The critical function can use the new set_month_zero()
and get_month_zero()
methods to do a zero-based manipulation of the month.