2.15.  Collections

[Warning]Text not verified for kermeta 2

Collections are widely used in Kermeta not only because of their usual usage for collecting data in variables but also because they are used to represent class property when the multiplicity is greater than 1.

Collections is one of the concept where the genericity is the most visible since it greatly helps to write more robust code.

2.15.1. Definition and initialization

Kermeta defines some collection data types handling sets of values. The different available collection types are the result of a combination of the constraints unique and ordered .

  • Unique specifies a collection type that cannot contain doublet

  • Ordered specifies a collection type where the position of an object inside the collection can be modified.

Name

Description

Constraints

Unique

Ordered

set

Represents an unordered collection of objects with no doublet (Set)

True

False

oset

Represents an ordered collection of objects with no doublet (OrderedSet)

True

True

seq

Represents an ordered collection of objects (Sequence)

False

True

bag

Represents a basic collection of objects (Bag)

False

False

: The Kermeta collections

Figure 2.4. : The Kermeta collections


Another way to define set of objects would have been to use arrays. In fact, Kermeta does not define explicitly the concept of array, but it provides a multiplicity concept which can be used instead. Multiplicities are a way to define a lower and upper bound on a collection. Syntactically, lower and upper bounds are defined between brackets and are separated by two dots. Bounds can be an integer literal value or a star to specify there's no upper bound.

Example 1 : how to declare collections

using kermeta::standard		// don't need to specify it all the time
	// This is the simpliest and recommanded way of declaring a collection variable
	var myColA : Set<Integer> // this is equivalent to saying set Integer[0..*]
	var myColB : OrderedSet<Integer> // this is equivalent to saying oset Integer[0..*]
		
	// Collection with multiplicities
    var myCol1 : set Integer[4..6] // At least 4 elements and never more than 6
	var myCol3 : seq String[2..*] // At least two strings in the sequence
	var myCol4 : set String[1..*] // An non empty set
	var myCol5 : String[1..*] // If you don't specify any keyword, it is an ordered set
        

There is currently no way to define a collection by extension like you can do in C or Java. You must initialize your collection either by calling new (Kermeta constructor operation) on your collection type, or initialize by copy.

Example 2 : initialize collections

// Example of declaration of variables as Collections. All those syntaxes are valid
var myCol1 : set Integer[0..*]    init kermeta::standard::Set<Integer>.new
// Fill in myCol1
myCol1.add(10)
myCol1.add(50)

var myCol2 : oset String[0..*]    init kermeta::standard::OrderedSet<String>.new
var myCol3 : bag Boolean[0..*]    init kermeta::standard::Bag<Boolean>.new
var myCol4 : seq Integer[0..*]    init kermeta::standard::Sequence<Integer>.new
// if no keyword specified, and multiplicity is set, it is an OrderedSet
var myCol4 : String[0..*] init kermeta::standard::OrderedSet<String>.new
var myCol1a : seq Integer[0..*]    init myCol1
var myCol2a : oset String[0..*]    init myCol2
var myCol3a : kermeta::standard::Bag<Boolean> init myCol3
var myCol3a : kermeta::standard::Sequence<Integer> init myCol4
[Note]Note

Conclusion : in most cases, you don't need to use this special syntax, you can simply use the generic collection names (Set<Something>, OrderedSet<Something>, etc.) available in Kermeta framework. Moreover, lower and upper bounds aren’t checked yet by Kermeta type checker and interpreter.

2.15.2. Some existing useful functions

The collections in Kermeta implement several functions based on lambda expressions (see Section 2.19, “ Lambda Expressions and functions ” ). These ones are very useful for model navigation.

2.15.2.1.  Function each

TODO

aCollection.each { e | 
	    /* do something with each element e of this collection */
}

2.15.2.2.  Function forAll

TODO

aBoolean := aCollection.forAll { e | /* put here a condition */
	} // return true if the condition is true for all elements in the collection.

2.15.2.3.  Function select

TODO

aCollection2 := aCollection.select { e | 
	     /* put here a condition that returns true for elements that must be included in the resulting Collection */
	}

2.15.2.4.  Function reject

TODO

aCollection2 := aCollection.reject { e | 
	     /* put here a condition that returns true for elements that must be exclude in the resulting Collection */
	}

2.15.2.5.  Function collect

TODO

 // return a new collection which size is the same as in the original 
			 // collection, and which element type is the type of the result of the expression.
			aCollection2 := aCollection.collect { e | 
			     /* put here an expression, for example e.name */
			}

2.15.2.6.  Function detect

TODO

anObject := aCollection.detect { e | /* a condition */} // returns an element (usually the first) that fulfills the condition.

2.15.2.7.  Function exists

Function exists returns true if at least one element fulfills the last boolean expression defined into the block. For instance:

aBoolean := aCollection.exists { e | /* a condition */} // returns true if at least one element fulfills the condition.

If several boolean condition are defined into the block of function exists , the last condition is used for the test. For instance, the following function exists returns true at the first iteration:

aBoolean := aCollection.exists { e | false true }

Instructions can be defined into the block of function exists . For instance, the following code displays the current object at each iteration:

aBoolean := aCollection.exists { e |
				stdio.writeln(e.toString)
				/* a condition */
			}
			

If no boolean expression is defined, value Void is returned, as illstrated in the following example. Such a use of function exists is not adviced since it corresponds to the use of function each .

aBoolean := aCollection.exists { e | stdio.writeln(e.toString) }/* The value of aBoolean is Void */