Variability Modeling DSL (VM-DSL) focuses on abstracting the realized variability in the code assets of a variability-rich system. It aims to capture and model the reusable structure of the code assets. The approach is based on abstracting the used variability implementation techniques coming from object-oriented or functional programming, such as inheritance, overloading, or software design patterns.


VM-DSL emerged during the research work on software product line engineering, specifically on understanding the variability implementation approaches of similar software-intensive systems.

Overview

Variability Modeling DSL (VM-DSL) is a domain specific language (DSL), realized in Scala language. Here are presented its main language constructs and an illustrative example of usage.

Availability

The VM-DSL is available for download from its Github repository.

* It is important to know that VM-DSL is an IntelliJ (2018.2.1) project. Therefore to use it easily you should install IntelliJ.

VM-DSL syntax

The detailed language syntax of VM-DSL is available. It can be used to realize the VM-DSL using another programming language.


Usage

Language concepts

By using the VM-DSL one can model the variability of code assets in a Java-based variability-rich system in terms of variation points with variants in a technical variability model tvm. According to their definition:
  • variation pointidentifies one or more locations at which the variation will occur.
  • variants express the way that a variation point is going to vary.
  • tvm stands for technical variability model, which consists of two parts:
    1. The captured abstractions of variation points with variants that are associated with the variable elements in reusable code assets, and
    2. The described dependencies of variation points with variants with their characteristic properties, such as logical relation, binding time, and evolution properties, using the fragment construct.

Set up of VM-DSL

The VM-DSL can be used to model the variability of a variability-rich system implemented in Java or Scala languages. In the following is shown its usage for modeling the variability of an illustrative system implemented in Scala.

To set up the VM-DSL

  1. Download the VM-DSL from its repository and add it in your project.
  2. Create a package named, for examle, tvm in your SPL project, which will hold the modeled variability.
  3. Then, for each subdomain of your choice, for example, for each package, you can create a new tvm_x.scala class to hold / model its variability.

Or, alternatively to steps 2 and 3, the VM-DSL can just be imported into the current scope, for example, package, file, or class, where variability needs to be separately abstracted within a tvm.

Usage pattern

Here is a pattern for using the VM-DSL:

  /* tvm_x.scala */
  import dsl._
  import scala.reflect.runtime.universe._

  <vp_name>        := <vp_type>(<tag to the variable asset>)
  <variant_name>   := Variant(<tag to the variable asset>)

  import dsl.fragment._
  fragment(<class | file | package name>) {
      <vp_name> is <logical relation> with_variants (<list of variant_name(s)>)
      use <technique> with_binding <binding time> and_evolution <evolution>
  }
  

Line 1: First, a tvm_x.scala class is created.

Line 2: tvm_x.scala class you need to import the VM-DSL.

Line 3: The VM-DSL use the reflection in Scala to tag the variable assets in code, therefore you need to import Scala reflection too. You may need to import also the subdomain, specifically the package, or class with variability (not shown here).

Lines 4 and 5: You need to create variation points and variants, respectively. First, you define them, by giving a name, and then you specify their type.

The VM-DSL supports five types of variation points:

VP   - Ordinary variation point, uVP - Unimplemented variation point, oVP - Optional variation point, tVP - Technical variation point, nVP - Nested variation point.

For abstracting variants, the VM-DSL provides the Variant construct.

The VM-DSL has an asset construct where you can use the reflection in Scala to tag the variability related class, method, or field in code assets.

Lines 6 to 10: Then, you import and use the fragment construct to model the variability in terms of the defined abstractions of variation points and variants.

First, the logical relation among the variants of a variation point are modeled. For this, there are available four logical relations among the variants of a variation point:

mandatory, optional, alternative, or.

Secondly is abstracted the used technique to implement a variation point with its variants. The current VM-DSL supports the five techniques (new techniques can be added and used too):

inheritance, overloading, overriding, strategy, template.

Thirdly, depending from the used technique, during the product derivation, variants can be bound at different times. The current VM-DSL supports two binding times:

compile_time and runtime.

Finally, a variation point can be open for evolution in the future or not, which property comes from the used technique. Therefore, VM-DSL has two possible evolution properties for a variation point:

open and close.

These four steps are repeated for abstracting each variation point with its variants and modeling the variability of some code assets.

Usage example

Here is an example of a variation point with three variants in code assets of a variability-rich system:

  /* Class level variation point, vp_AbsLine2D */
  public abstract class AbstractLine2D extends 
    AbstractSmoothCurve2D implements 
    SmoothOrientedCurve2D, 
    LinearElement2D {

      /* First variant of vp_distance */
      public double distance(Point2D p) {
        return distance(p.x(), p.y());
      }
      
      /* Second variant of vp_distance */
      public double distance(double x, double y) {
          Point2D proj = projectedPoint(x, y);
          if (contains(proj))
              return proj.distance(x, y);
          /* Omitted code */
          return dist;
      }
    /* Omitted code */
  }
  
  /* First variant, v_Line2D, of vp_AbsLine2D */
  public class StraightLine2D extends AbstractLine2D implements 
    SmoothContour2D, Cloneable, CircleLine2D {
	  /* Omitted code */
  }
  
  /* Second variant, v_Segment2D, of vp_AbsLine2D */
  public class LineSegment2D extends 
    AbstractLine2D implements Cloneable, CirculinearElement2D {
	  /* Omitted code */
  }
  
  /* Third variant, v_Ray2D, of vp_AbsLine2D */
  public class Ray2D extends AbstractLine2D implements Cloneable {
	  /* Omitted code */
  }
  

The variability of these code assets is modeled as in the following:

  /* tvm_line.java*/
  package tvm  // For example, all TVMs are kept within a package
  import dsl._
  import scala.reflect.runtime.universe._
  
  val vp_AbsLine2D   = VP(asset(typeOf[AbstractLine2D].typeSymbol))
  val v_Line2D       = Variant(asset(typeOf[StraightLine2D].typeSymbol))
  val v_Segment2D    = Variant(asset(typeOf[LineSegment2D].typeSymbol))
  val v_Ray2D        = Variant(asset(typeOf[Ray2D].typeSymbol))  
  
  import fragment._
  fragment("geom2D.line") {
    vp_AbsLine2D is ALT with_variants (v_Line2D, v_Segment2D, v_Ray2D) use
    INHERITANCE with_binding RUN_TIME and_evolution OPEN
  }