I have a question about the OOP principle of data hiding.
As far as I understand, data hiding = restrict internal fields of a structure to a certain area of visibility. Motivation: if one changes structure contents, only implementations in the area of visibility have to be changed.
In order to enforce data hiding principle, oop designers mostly decided to do this:
Approach 1:
Encapsulation = make the area of visibility the struct itself (class), put functions (methods) that operate on it inside.
This seems like a very big requirement to me. and creates a lot of unecessary assymetry. Why didn't OOP designers decide instead to define encapsulation in this way:
Approach 2:
Give the programmer control on what the area of visibility should be. An area of visibility might include several structs, not just one. define functions in this area of visibility that may operate between several structs. This way struct, and functions are living more independently, there is more symmetry, fewer getters/setters might be needed.
Let me give you an example: If you have a glass object and a bottle object that internally contain some water quantity. Say you want to implement an ability to fill the glass from the bottle.
With approach 1, you are forced to do something asymetric, you must either implement glass.fill(bottle) or implement bottle.fill(glass), so it sounds like you have an unecessary dilemma to resolve. Not only that, say you implement glass.fill(bottle), now you are in glass's scope, you cannot access bottle's internals, so you are forced to write a method in bottle, in order to be able to update it. It sounds to me like a lot of unecessary work, and this forced bottle.update method sounds more detrimental to data hiding.
With approach 2, you can just define an independent fill(glass, bottle) that might just know about glass and bottle's internals as glass, bottle and fill could be part of the same area of visibility. Doesnt that sound much easier? Note that you could still define protocols (interfaces) with this approach, Externally all you need to know is that glass and bottles are unspecified things, and fill is an operation that operates on two things: a glass and a bottle.
Are there any flaws in my argument? Are there any attempts of programming languages that emphasize this sort approach?