Moved from RelationalBreaksEncapsulation
It seems that CollectionOrientedProgramming
in general breaks encapsulation, not just relational in particular. It is wider than that. The rules or interface for handling the "cells" as groups are on the outside, while OO wants them to be inside because each object is supposed to handle its own affairs. But if they are inside, then it is hard for the outside operations to operate consistentantly for each cell and take advantage of parellel processing, indexing, and other techniques that require a central or controlled view of collections to work effectively. In my observation, it seems that CollectionOrientedProgramming
to give each "thing" common or standard operations for handling typical collection operations. It is hard to have an efficient collection-based system without dictating operations on the cells, but such dictation requires something outside the cell to tell it how to handle collection-oriented stuff. This is what busts encapsulation
. Collection orientation requires "exocapsulation", that is CollectionOrientedVerbs
are like an exoskeleton that binds the "objects". The cell is not allowed to handle its own collection affairs, at least not without violating "collection norms" and possibly reinventing the wheel. It is a philosophical divide over internal responsibility versus dictated collection-oriented norms. -- top
Not really. It depends on what you want to do with collections; in many cases, collections are little more than holders of arbitrary entities and need not care one whit about the entity being held. Of course, the RelationalModel
(more specifically, the RelationalAlgebra
) defines several operations on relations which do
"break encapsulation". More specifically, it required that the items collected within a given relation be records whose internal structure be visible. This is necessary to support relational operations like join, project, select, etc.
For each of those, however, a more generic "object" analog can be constructed (wherein it is assumed a container can hold arbitrary objects, we still assume here that the outer container is a set and thus the contained objects are unique).
But what is "doing" these things? Not the objects themselves. COP is usually driven by a god-like outer service, not each object's methods. It seems a database is being reinvented. What about concurrency issues and all the features listed in DatabaseDefinition? Can you get these without a DiscontinuitySpike?
- A relational SELECT is analogous to the "filter" HigherOrderFunction as found in most OO and functional languages. Given a set and a predicate, return a new set containing all elements of the original set which satisfy the predicated. In relational (SQL actually), the predicate is a WHERE clause specifying constraints on the individual attributes in the record; but any predicate will do.
- A relational PROJECT is analogous to the HigherOrderFunction "map"/"mapcar"/"foreach", modified to be set-friendly (removing duplicates that might be generated by the transformation function). Given a set and a transformation function; apply the transformation function to each element of the original set, returning a set containing the transformed elements (and duplicates removed). The transformation function in a relational select is constrained to be generation of a new record with zero or more attributes elided.
- A relational JOIN is a bit trickier to model more generically. One (very general) way to do it is to form the CartesianProduct of the two sets, filter out those without required joinability (without the desired attributes in common in relational terms), and then perform a projection to put the result in the final form.
- Without a lot of ugly behind-the-scenes "faking it", that would be very inefficient.
- And "totalling" in the relational world is of course equivalent to the HigherOrderFunction fold(l/r) or reduce.
- What does that matter? Other objects/functions aren't barred from manipulating objects; they just have to do it using an object's exposed interface (if encapsulation is to be respected).
- If every object "inherits" the collection-orientation's minimum necessary interface for consistent COP behavior and expected efficiencies, then it is not using the "spirit" of OOP. It might not even work on some languages that are otherwise fully considered OOP. If we don't have multiple inheritance, for example, then we'll spend all our inheritance on the COP-related operations and have none left over for domain inheritance. We essentially need good support for a God Class (global master automatic class) to do it effectively.
- And what's mentioned above is functional programming, not OOP. A language can be OOP without supporting FP. Thus, you are talking more about properties of FP than OOP. You have to steal a neighbor's expert to pull it off.
- Both of the arguments you just presented could be applied equally to complain that integers and simple maths conflict with both collections and OO. (Does every object/collection inherit the integer interface? WTF?!) It's fatuous nonsense. Whether OOP "effectively supports" collections is an entirely different question from whether it "conflicts with" the same.
But two things are happening:
- The interface has to respect the "global" collection interface. In COP the cells automatically get these, we don't have to rely on volunteerism.
- Efficiency tricks such as parallelization may not be possible or easy if each object does its own. A behavioral interface may ignore cross-node coordination issues that are often involved in efficiency tuning. If we include enough details in the interface to obtain satisfactory efficiency, then we may be dictating implementation, which violates the spirit of encapsulation (which relates to ADT swappability), and/or creating an interface mess.
- Not always clear where things such as totals and other aggregates are stored or handled.
I agree that if one bends and twists OOP enough, it may be able to pull off decent COP. But the fact that it has to be bent, twisted, and perhaps "polluted" with functional programming generally demonstrates my point. I'm pretty sure most any paradigm/style can be pounded into anything else if we push the edges of the definitions or accepted characteristics to their edge. The issue is how much force-fitting is required. -t
There are more ways of combining OOP and COP in heaven and earth than are dreamt of in your philosophy. For example: Collections as FirstClass objects, and collections OF opaque object references.
Perhaps we can divide it into "OOP as commonly-used" and "potential".
Sure. OOP as commonly-used (i.e. in Java, C++, C#) utilizes structured collections of opaque object references. This is called "GenericProgramming". The collections themselves are represented by FirstClass objects. Historically, collections are mutable objects, but the growing use of concurrency has encouraged many OOP languages to focus on immutable collections (collections as ValueObjects) using CopyOnWrite and similar techniques. The result is a hodge-podge of collection implementations that have funky safety and performance characteristics (especially under conditions of concurrency and mutation) - i.e. OOP as commonly used does not handle collections very effectively. But there are no conceptual barriers against an OO language coming boxed with high-quality FirstClass collections (perhaps even relations or tables) in the same sense that OO typically comes boxed with support for integers. Thus, there is no fundamental difficulty combining OO and Collection Orientation.
What you want to do is claim: "but my collections interface won't be able to peek inside the objects!". Sure. That's the point of encapsulation, after all. But that's not a valid argument for 'conflict' because both objects and collections will still coexist peacefully in the same system. That is, the argument "CollectionsArentOo" has merit, but the argument "OoConflictsWithCollectionOrientation" does not.
Opaque objects tend to be object wrappers. It may not be making the OOP be COP, but rather putting an OO wrapper on top of COP.
What do you mean by "object wrapper"? In any case, "conflict" would mean there is some problem with having both OOP and COP coexist in a system. Would you say COP conflicts with integers and characters and booleans?
See also: CollectionsArentOo