[Object-Oriented Data Abstraction is all about Behavioral Abstraction](http://CS.UTexas.Edu/~wcook/Drafts/2009/essay.pdf). The implementation details are hidden behind a behavioral interface, i.e. an interface that *does something*. A variable is not behavior, it is state. A getter or setter is just a variable in disguise. The question is: "what does a `Point` *do*", *not* "what state does it have". For example, how would you compute a new point from an existing point? You have no choice but to "take apart" the point, do all the necessary calculations yourself, then put the point back together again. And you have to do this in *every single piece of code* that wants to somehow create new points from old ones. And what happens if you decide that representing points as cartesian coordinates is inefficient and you would rather represent it using polar coordinates? But, what if the point wasn't just a "dead" bag of data? What if the point had behavior? What if it knew *itself* how to construct a new point from itself? For example, we can get a new `Point` by adding a displacement vector. So, we add an `add` method to the point which takes a displacement vector as a parameter (example in Scala, but it doesn't matter): <!-- language: lang-scala --> class Point(val x: Double, val y: Double) { def +(v: Vector) = ??? } Now, any piece of code can create a new point by taking an existing point and adding a displacement vector to it, without having to know *anything* about how `Point`s or `Vector`s work. You can freely change the implementation and representation of either or both, without affecting *any* other code. If you know a bit of Scala, you may have noticed that I had Scala generate automatic getters for `x` and `y`. I feel that's okay, because you sometimes *do* want to work with them separately. I did, however, *not* generate setters! If we take something more complex, like a collection interface, it becomes even more apparent. How would you rather traverse a linked list: // without abstraction: var node = list.head while (node != null) { println(node) node = node.next } // with abstraction: list.foreach(println) Not only is the code using the abstracted behavioral interface much simpler, it also works for *any* collection, not just for lists. The collection data structure itself can decide how to execute the traversal most efficiently, for example, it could decide to execute it in parallel on multiple CPU cores. There is a better example of this principle in action in the seminal paper [*On Understanding Data Abstraction, Revisited*](http://CS.UTexas.Edu/~wcook/Drafts/2009/essay.pdf) by [William R. Cook](http://WCook.BlogSpot.Com/), in which Cook explains the fundamental difference between Object-Oriented Data Abstraction and Data Abstraction based on Abstract Data Types. Unfortunately, many textbooks treat Objects as only a slight variation of ADTs (e.g. "Objects = ADTs + Inheritance"), or even one and the same, but they are in fact *fundamentally* different. [*On the Criteria To Be Used in Decomposing Systems into Modules* by David Parnas](http://www.cs.umd.edu/class/spring2003/cmsc838p/Design/criteria.pdf) is also still a good read, even 45 years later.