How will encapsulation help when making changes in code and from its
rippling effects. For a data member, if I change its type from int to
float, (even if I am exposing this using property) I will need to
change variable type where I am using already using this code.
The benefit of encapsulation is that it lets you change the internal implementation without breaking client code. It doesn't protect you if you decide that you need to change the interface to your code, but that's a different matter.
Example: Say you have a value representing the price per unit of some commodity. The price is expressed in cents, and because you don't deal in fractional cents you decided to make the property an integer (I'll use C here because I'm not very familiar with C#):
int _price
int pricePerUnit(void) {
return _price;
}
int priceForUnits(int units) {
return units * _price;
}
That all works out fine until one day when somebody notices that your firm is losing a lot of money due to rounding errors. Many of the commodities that you track are bought and sold in lots of many thousands of units, so you need to start tracking the price to an accuracy of at least 0.001 cent. Because you were smart enough to encapsulate the price instead of letting clients access it directly, you can make that change pretty quickly:
double _dprice
int pricePerUnit(void) {
return (int)_dprice;
}
int priceForUnits(int units) {
return (int)(units * _dprice);
}
The interface that clients use to obtain prices stays the same, but the data they get back is now more accurate. If the price per unit is $1.001, priceForUnits(1000000)
will now return a price that's $1000 greater than before. That happens even though you haven't changed the interface to your system at all, and you therefore haven't broken any client code.
Now, that may not always be all that you need to do. Sometimes you'll need to change or augment your interface so that you can report the price more accurately to clients, too:
double pricePerUnit() {
return _dprice;
}
A change like that will break client code, so you might instead keep the old interface and provide a newer, better routine:
int pricePerUnit() {
return (int)_dprice;
}
double accuratePricePerUnit() {
return _dprice;
}
You and the rest of your team can then embark on the process of converting all the clients of your system to use the newer, better accuratePricePerUnit()
. The client code will get more accurate as you make progress on that task, but even the old stuff should continue to work as well as it did in the past.
Anyway, the point is that encapsulation lets you change the way the internals work while presenting a consistent interface, and that helps you make useful changes without breaking other code. It doesn't always protect you from having to update other code, but it can at least help you do that in a controlled manner.
At a first glance, these two lines may look the same:
public string A;
public string B {get; set;}
but they're not the same at all. As you'll know, if you use a public field and in the future you need to add some logic when getting or setting the value, you can't (unless you break the interface that you're providing to others). You can't, because the value isn't encapsulated.
With an automatic property, instead, you can add more logic whenever you want, without the need to change the interface that your class provides. Just replace the automatic property with a standard one. Or, vice-versa, you can replace the standard property with an automatic one. To an external user, nothing changes.
So no, you're not even remotely breaking encapsulation. You're just using an handy syntactic sugar.
Best Answer
It's all about Encapsulation and the Uniform Access Principle.
An object should be able to respond to a message by either returning existing data or running a method, but the sender shouldn't be able to tell which is which. Or if you view this from the sender's side: the sender should be able to access existing data or run a method through a uniform interface.
There are several ways to achieve this:
get rid of data altogether, just have methods (Newspeak does this)
get rid of methods altogether, just have data (Self does this, "methods" are just
Method
objects assigned to instance variables, instance variables are looked up with virtual dispatch)make no syntactic or semantic distinction between methods and data (Scala does this, accessing a field is syntactically indistinguishable from calling a method without an argument list (
foo.bar
), assigning to a field is syntactically indistinguishable from calling a specially named method (foo.bar = baz
) is the same asfoo.bar_=(baz)
i.e. calling a method namedfoo_=
, and read-only values can be overridden or implemented by a method without parameter list (i.e.val foo
) in a superclass can be overridden (or anabstract
val
be implemented) in a subclass with a methoddef foo
)Java, however, doesn't follow the Uniform Access Principle. In Java, it is possible to distinguish between accessing data and running a method.
foo.bar
is different fromfoo.bar()
. The reason for this is that fields and methods are semantically and syntactically distinct.C# tries to fix this by adding properties to the language, basically methods that look like fields. However, method calls still look and feel different from field and property accesses. Fields and properties now have Uniform Access, but methods still don't.
So, this doesn't actually fix the problem: you cannot fix having two different ways to access things by adding a third way to access things! Even if that third way looks like one of the other two ways, you will still have (at least) two different ways. You can only fix it by either getting rid of all the different ways except one or get rid of the differences.
It's perfectly fine to have a language with methods, properties and fields, but all three should have uniform access.