commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Brian McCallister <>
Subject Re: [collections] [contribution] CompositeSet and CompositeMap
Date Tue, 09 Dec 2003 04:46:18 GMT
On Dec 8, 2003, at 10:38 PM, Phil Steitz wrote:

I missed your earlier comments, unless you mean on the 
CompositeCollection submission.

> * Please try to follow the [collections] style for braces.

No problem, I figured this was just an autoformat via tool of choice -- 
can do so if it needs it. I (maybe mistakenly) assumed that anyone 
reading it would autoformat it to their preferred format anyway, and as 
only a collections committer can check it in -- his or her autoformat 
will work fine.

> Why does CompositeSet extend CompositeCollection? The setup looks a 
> bit strained to me (e.g. the type checking in the addComposited 
> method).

As the majority of the behavior is identical behavior inheritance make 
sense in this context. The only behavior that changes is the 
calculation of equals() and hashcode(), and the requirement that 
elements be unique. Really the composited elements don't NEED to even 
be sets, but it is convenient for avoiding the situation where 
modification of the underlieing data structure invalidates the internal 
state of the composite. An inheritance by delegation would allow the 
reuse of behavior at the expense of more code and would allow typesafe 
addComposited(...) if you mind this. It is more code in that you need 
delegating stubs, but is a minor point.

> Looking carefully at what addComposited does in CompositeSet, I am not 
> sure that I understand what CompositeSet and CompositeMap are trying 
> to do.

They do the same things. Collision handling was added as a convenience 
-- the default behavior is to throw an IllegalArgumentException if 
there is nothing set to handle the collision. The collision handling 
came from a requirement in my original implementation. If you feel it 
muddies the implementation rather than add useful features remove it. 
In the original implementation it was separate from the concept of the 
strongly typed Mutator interface that Stephen introduced to the 
CompositeCollection which could be used separately from the mutators 
(which were specified per-method rather than via a strongly typed 

> I understood CompositeCollection to be a convenient way to decorate a  
> collection of Collections to provide a unified view.  Once you try to 
> control "collisions", as in the Set and Map impls, you seem to be 
> headed for some kind of partition concept.  Is that what you had in 
> mind?

There is a degree of partitioning that needs to occur - hence having 
the mutators undefined by default, but allowing definitions. There are 
really two concepts at play here. The first is the composite concept, 
the second is mixing in implementations of the mutators -- it 
externalizes the mutation operations as on a composite they are pretty 
much always special case operations if they are supported. The easier 
solution is to make composites immutable -- but as I mentioned, when 
originally developed I needed them to be mutable.

>  Also, since add() and resolveCollisions() are separate methods in the 
> mutator interface, one could presumably do inconsistent things -- 
> i.e., allow "duplicates" to be added directly via add() but disallow 
> them in addComposited() by having resolveCollisions prevent 
> duplicates.

You are correct that people could break the class if they wanted to. 
The default behavior is to disallow mutators (OperationNotSupported), 
and to throw an IllegalArgument on collisions. If you accept 
responsibility for mixing in mutators you need to be willing to solve 
that problem I think. Disabling mutators completely by dropping the 
ability to specify mutators is an option, and prevents people from 
hurting themselves, but I personally prefer to allow them hurt 
themselves if they have to work to do it (separately define mutators), 
and keep the classes more flexible and powerful.

> Can you explain a little more what the use cases for these things are?

A lot of the uses grow out of the limitations of O/R mapping. The 
typical case in which I have used them is in hierarchical aggregates 
mapped to objects from a relational database. This case has occurred 
several times in different projects I have worked on, here is a typical 
example where a Group has members but it needs to include its 
children's members in the ones it presents to clients (Group in this 
case decorates a single instance, itself, and additional child 
instances) :

class Group
	private Set members;
	/** Instances of Group */
	private Set children;

	public Set getMembers() {
		CompositeSet set = new CompositeSet(members);
		// Would add collision handling and mutators if real
		for (Iterator i = this.children.iterator(); i.hasNext();) {
			set.addComposited( ((Group);
		return set;

Specific behavior designed for includes supporting lazy-loading of the 
composited collections (don't get more information than is absolutely 
needed for a given operation as the database hit is typically far worse 
than the extra calculation), degradation of behavior as circumstances 
get unusual (collisions)  but not downright broken (exceptions) rather 
than breaking for special cases (ie, in the above example, a member 
appearing at multiple levels of the hierarchy), and the ability to 
change how mutations work based on a lot of different criteria 
(factory/builder for mutators). Basically really flexible collections 
that composite nicely.

An additional use case is in an SQL generator that functions via a 
query-by-criteria with automatic reordering of elements based on where 
they belong in the query. Composited collections of query elements 
(columns, tables, sub-selects (with the full panoply of elements), join 
criteria, where criteria, etc) allow for maintaining a flexible model 
of the query at any given time but still be able to access all parts 
for nice things like extracting token replacements for mapping prepared 
statement binding values to the correct place in the query when it is 
actually bound. (I cannot open up this particular library at the moment 
  as it was done on company time and is the company's IP)

If there is violent opposition to adding these, by all means please 
don't. I'm just trying to make available resources that I thought would 
be helpful and to my mind fit in well with things already in 


To unsubscribe, e-mail:
For additional commands, e-mail:

View raw message