Aggregating feature chains can result in surprising results, as multiple paths with the same start and end elements are merged together. This can be caused by (1) having multiple EObject instances reachable with the same checked attribute value (e.g. multiple machines with the same amount of RAM) or (2) reaching the same object in multiple paths. The duplicates can be correctly handled by making all objects through the path parameters, but the embedded aggregation syntax does not provide such support.

To demonstrate the issue, consider the following query (based on the CPS domain): we are interested in the total amount of RAM available in hosts of a dedicated host type. Naively, we could write the following query:

pattern hostTypeRAMTotal_Wrong_Embedded(ht : HostType, total : java Integer) {
	total == sum HostType.instances.totalRam(ht, #);
}

However, this results in an incorrect match set if there are multiple host instances of the same host type that have the same value assigned to the total RAM attribute.

Match set of the embedded subpattern

This embedded query is equivalent of the following version without embedded aggregation:

pattern hostTypeRAM_Simple(ht : HostType, ram : java Integer) {
	HostType.instances.totalRam(ht, ram);
}

pattern hostTypeRAMTotal_Wrong(ht : HostType, total : java Integer) {
	total == sum find hostTypeRAM_Simple(ht, #);
}

The problematic part is the hostTypeRAM_Simple pattern where the removal of the interim host instance variable results in multiple rows having the same value:

Match set with the helper pattern

By modifying the called pattern not to remove the host instance variable, the result set becomes the expected one:

pattern hostTypeRAM(ht : HostType, hi : HostInstance, ram : java Integer) {
	HostType.instances(ht, hi);
	HostInstance.totalRam(hi, ram);
}

pattern hostTypeRAMTotal(ht : HostType, total : java Integer) {
	total == sum find hostTypeRAM(ht, _, #);
}
Match set with the fixed pattern