FAMILIAR Tutorial

Through small examples, the various types, operations and programming mechanisms of FAMILIAR are introduced.

At the end of the tutorial, you should be able to program a parameterized script which replaces a "subtree" in a feature model by another feature model.

replacing a subtree in a feature model

Types and Variables

FAMILIAR is a typed language, with Feature Model, Feature and Configuration types. Utility types are also provided including String (e.g., feature names are strings) and generic Set to represent container values. Primitive types are also present including Boolean, Integer and Real. An example script fragment that illustrates typing is given below:

Accessors: operations on types

Lines 1-4 define two variables of type Feature Model: gc1 and gc2. The content of a variable with primitive type (including String) is treated as a value whereas variables of complex types contain references (e.g., gc1 contains a reference to a feature model). Lines 5 and 6 illustrate reference equality (eq) and content equality (==). Lines 7 and 8 contain variables of type String (str) and Set (fmSet is a set of feature models).

Types have accessors for observing the content of a variable. The example below illustrates the use of accessors :

Accessors: operations on types

At line 3, variable f1 records a reference to feature directX (the parent of feature v11). (The name of a feature is unique within a feature model and is used to identify a feature.) At line 4 variable f2 contains a reference to the feature GraphicCard (the root of feature model referenced by the variable gc3). The remaining lines (5-7) illustrate operations returning i) the name of a feature, ii) the set of direct subfeatures of a given feature and iii) the cardinality of a set.

Operations

Modifying feature models

The language provides operations for renaming and removing features in feature models. Renaming is particularly important when composing several feature models where it cannot be guaranteed that the developers will use the same name for the same feature. The following illustrates how features can be renamed:

Modifications of feature models

In lines 1-3, the feature Bus of feature model gc3 is renamed to "MemoryBus" by concatenating the string Memory with the old name Bus. The operation assert at line 4 stops the program with an appropriate error message if the renaming is not successful (i.e., b1 is false).

Similarly, the operation removeFeature takes a feature as an argument and removes the feature and its subfeatures from the feature model it belongs to (see also below). It also returns true or false depending whether it is successful or not.

Handling feature model configurations

The language also allows developers to create feature model configurations, and then select, deselect, or unselect a feature. Each of these configuration manipulation operations returns a boolean value to notify success or failure, i.e., if a feature does not exist in a feature model. (There is no failure if the selection or deselection of feature leads to an unvalid configuration -- see isValid). An example usage of these operations is given below:

Configuration and operations

At line 1, the operation configuration creates and initializes a configuration of the feature model gc1. Lines 2-4 provide examples of the configuration manipulations.

Reasoning about feature models

FAMILIAR provides several operations to support reasoning about feature models. The script fragment below provides examples of the feature model manipulation and reasoning operations:

Basic operations

Line 2 computes the number of valid configurations of gc1. The isValid operation checks whether a configuration is valid (see line 3) according to its feature model. The isValid operation can also perform on a feature model and determines its satisfiability, i.e., whether or not there is at least one valid configuration.

FAMILIAR also provides an operation that checks whether a configuration is complete, i.e., whether all features have been selected or deselected. In addition, the Configuration type provides three accessors that return the set of selected, deselected and unselected features: selectedF, deselectedF and unselectedF. Line 4 checks that the set of selected features in both conf1 and conf2 are equal (which is true simply because conf2 is a copy of conf1). The compare operation is used to determine whether a feature model is a refactoring, generalization, or specialization of another feature model. This operation is based on the algorithm and terminology used in the paper  Thomas Thüm, Don Batory, and Christian Kästner. Reasoning about Edits to Feature Models (ICSE'09). Let f and g be FMs, and let [[f]] (resp. [[g]]) denote the set of configurations for f (resp. g); f is a specialization of g if [[f]] is included in [[g]] ; f is a generalization of g if [[g]] is included in [[f]] ; f is a refactoring of g if [[f]] is equal to [[g]]. Line 5 illustrates comparison capabilities based on sets of configurations of feature models. In addition, FAMILIAR provides i) a conditional construct : a classical if then else and ii) a foreach loop which can be used to iterate over a set of variables (e.g., representing feature models, features, and configurations) to perform a sequence of operations.

Loop

Line 1 gathers in varset all the features of gc1. Each feature of varset is then attached to f so that its name becomes prefixed with "new_".

Composition

The insert operator produces a feature model by inserting a feature model into another base or target feature model. The operator takes three arguments: i) the feature model to be inserted ii) the feature in the base/target feature model where the insertion is to take place, and iii) the operator (e.g., Xor) that determines the form of the insertion. The precondition of the insert operator requires that the intersection between the set of features of the base feature model and the one of the aspect feature model is empty. This condition preserves the well-formed property of the composed FM which states that each feature's name is unique. If this pre-condition is not respected or features arguments does not exist in the base or aspect models, insert returns false. The base feature model is modified if the insertion succeeds. An example script fragment describing an insertion is given below:

Feature model insertion

In the example, the feature Lang is inserted below the feature International (line 3): Lang is a child feature of International with the mandatory status, i.e., the selection of International implies the selection of Lang. The assert operations are used to check that the composition produced a feature model with specified properties.

Merging feature models

When two feature models share several features and present different views of a system, the merge operator can be used to merge the two feature models and obtain an integrated feature model of the system. The merge uses a name-based matching: two features match if and only if they have the same name. Several modes are defined for this operator.

The intersection mode is the most restrictive option: the merged feature model, FMr, expresses the common valid configurations of FM1 and FM2, i.e., a configuration that is valid in FM1 and FM2 is also valid in FMr. The union mode is the more permissive option: the merged feature model can express either valid configurations of FM1 or FM2, i.e., a valid configuration of the merged FM, FMr, is valid either in FM1 or FM2. A more restrictive property, called strict union mode, requires that the set of configurations of FMr is exactly the union of sets of configurations of FM1 and FM2. In the diff mode, the merge operator takes two input feature models, FM1 and FM2, and computes the set-theoretic difference of FM1 and FM2. The variability information associated with features in the merged feature model is different according to the merge mode and the properties that one wants to preserve. In the table below, the properties of the merged feature model is summarized with respect to the sets of configurations of two input FMs and the mode.

Merge operators: properties and notation

In FAMILIAR, the merge operators act on (a set of) feature models or configurations and produce feature models with semantics properties according to the mode specified by the user. Below is part of a script that uses a merge operator:

Merging feature models

Inter-relate feature models

Another form of composition can be applied using cross-tree constraints between features so that separated FMs are inter-related. The operator aggregate is used for producing a new FM in which a synthetic root relates a set of FMs and integrates a set of propositional constraints. All reasoning operations (e.g., counting, isValid) can be similarly performed on the new FM resulting from the aggregation.

Modularization mechanisms

Statements are organized in scripts. FAMILIAR provides modularization mechanisms that allow for the creation and use of multiple scripts in a single software product line project, and that supports the definition of reusable scripts. These mechanisms provide scalable support for developing and manipulating large feature models.

Namespace and Script Calling

Peviously, only feature names were used to identify a feature within a script.

FAMILIAR also supports the use of namespaces to manage naming of variables. For example, namespaces can be used to disambiguate names when features that have the same name are used by feature models referred to by different variables.

A namespace is attached to each variable so that it is possible to identify a feature by specifying the name of the variable followed by .. An example is given below:

Namespace

Lines 1-3 illustrate the use of namespace: Features DirectX and GraphicCard are common to gc1 and gc2 and are identified thanks to the namespace, while v11 appears only in gc3 and is non-ambiguous.

The example below is used to illustrate how FAMILIAR supports the reuse of existing scripts and incremental development of FMs:

Script calling

Line 1 shows how to run a script contained in the file script1.fmm from current script. Variable name conflicts may occur, especially when it is necessary to run the same script several times (see discussion on parameterizable scripts below). FAMILIAR relies on variable namespaces to distinguish the different versions of the script variables. The type Script is thus available and the name of a variable may be associated to it (see "script_declaration" at line 1). This variable then records the state of the script script1.fmm after it is run. In addition, FAMILIAR allows a script writer to use a wildcard "*" to define a set of elements (e.g., feature models, features). It may be placed just after "." or anywhere within a variable or feature name. For example, lines 2 (resp. 5) access the set of all variables of script_declaration (resp. all variables starting by gc in script_declaration).

By default a script makes visible to other scripts all its variables. Using export with several variable names means that only those variables remain visible. Using hide instead means that all variables mentioned are not visible.

Parameterized script

A script is customizable when some of its variables are defined as parameters (see lines 1-3 below). A parameter records a reference or a value that cannot be modified by the script. Lines 5-10 implement the replacement of a subtree rooted at the feature named f (in the feature model target}) by the feature model fmToInsert:

Parameterized script

Type Script and script parameters allows with a small syntactical extension to assign a statement sequence to a variable of type Script. It is then possible to describe a library of operations within one script.

Calling the parameterized script

The example below is used to illustrate how the previous script can be called with effective parameters:

Calling the parameterized script

see also children, extract, etc. or more generally the reference manual

Attachments