=Paper= {{Paper |id=Vol-2019/multi_7 |storemode=property |title=DeepRuby: Extending Ruby with Dual Deep Instantiation |pdfUrl=https://ceur-ws.org/Vol-2019/multi_7.pdf |volume=Vol-2019 |authors=Bernd Neumayr,Christoph G. Schuetz,Christian Horner,Michael Schrefl |dblpUrl=https://dblp.org/rec/conf/models/NeumayrSHS17 }} ==DeepRuby: Extending Ruby with Dual Deep Instantiation== https://ceur-ws.org/Vol-2019/multi_7.pdf
                        DeepRuby: Extending Ruby with
                            Dual Deep Instantiation
                               Bernd Neumayr                                                  Christoph G. Schuetz
                Department of Business Informatics – Data &                       Department of Business Informatics – Data &
                          Knowledge Engineering                                             Knowledge Engineering
                      Johannes Kepler University Linz                                   Johannes Kepler University Linz
                               Linz, Austria                                                     Linz, Austria
                          bernd.neumayr@jku.at                                             christoph.schuetz@jku.at

               Christian Horner                                                   Michael Schrefl
Department of Business Informatics – Data &                         Department of Business Informatics – Data &
          Knowledge Engineering                                               Knowledge Engineering
      Johannes Kepler University Linz                                     Johannes Kepler University Linz
               Linz, Austria                                                       Linz, Austria
                                                                              michael.schrefl@jku.at


   Abstract—Clabjects, the central construct of multi-level mod-    ultimate instance of the clabject or property. For example,
eling, overcome the strict separation of class and object in con-   clabject CarModel with potency 2 is instantiated by BMW Z4
ceptual modeling. Ruby, a dynamic object-oriented programming       with potency 1 which is in turn instantiated by Peter’s Car
language, similarly treats classes as objects and thus appears as
a natural candidate for implementing clabject-based modeling        with potency 0. Clabject CarModel defines a property engine
constructs. In this paper we introduce DeepRuby, a Ruby             with potency 2 and target EngineModel which is instantiated
implementation of the core constructs of Dual Deep Instantiation:   by BMW Z4 has engine EngineK5 and in turn by Peter’s Car
clabject hierarchies and attributes with separate source potency    has engine Engine123; Engine123 is an instance of EngineK5
and target potency. DeepRuby represents clabjects at two layers:    which is an instance of EngineModel. Clabject CarModel
the clabject layer and the clabject facet layer. At the clabject
facet layer, a clabject with maximum source potency i-1 and         further defines a property listPrice with target currency value
maximum target potency j-1 is represented by a matrix of i × j      and potency 1 which is instantiated by BMW Z4 has list price
clabject facets organized using Ruby’s superclass and eigenclass    e 42,232.
constructs. Clabject facets can easily be extended with behavior       Dual Deep Instantiation [9] (DDI) allows to specify the
implemented in custom methods.                                      number of instantiation steps separately for the source and for
   Index Terms—Object oriented programming, Metamodeling
                                                                    the target of a property. For example, clabject CarModel, as
                                                                    source, introduces property owner with source potency 2 and
                      I. I NTRODUCTION
                                                                    target Person with target potency 1. This property is ultimately
   Object-orientation is arguably the most important paradigm       instantiated between instances of instances of CarModel as
in programming and conceptual modeling. Statically-typed            source and instances of Person as target, for example by Peters
object-oriented programming languages, like Java, and tradi-        Car has owner Peter. Clabject CarModel further has a self-
tional conceptual modeling approaches, like E/R and UML,            describing property creator with source potency 0 and target
come with a strict separation between class and object. The         Person and target potency 1. This property is instantiated
clabject as central construct of multi-level modeling [10] over-    between CarModel as source and an instance of Person as
comes this separation and not only plays the roles of class and     target, for example by CarModel has creator Peter.
object but also of metaclass, potentially at many classification       In previous work, we formalized different variants of DDI
levels. Extending traditional modeling/programming languages        in deductive database languages, namely F-Logic [9] and Con-
to supporting clabjects is difficult, due to this inherent mis-     ceptBase [11], but without support for implementing behavior.
match. Dynamically typed languages like Ruby overcome the           In this paper we introduce DeepRuby, an implementation of
strict separation between object and class: classes are also        DDI in Ruby that supports the implementation of custom
treated as objects and may be extended at runtime. Based on         methods. DeepRuby makes heavy use of Ruby’s dynamic
this kinship, Ruby suggests itself as a suitable language for       programming and metaprogramming facilities [12]. The Deep-
implementing multilevel modeling constructs.                        Ruby version presented in this paper only implements a subset
   Deep Instantiation [2] is one of the most prominent ap-          of DDI: it does neither support clabject generalization nor
proaches to multi-level modeling. A potency assigned to a           multi-valued attributes. These simplifications allow to set the
clabject or property indicates the number of instantiation          focus on the following core idea of DeepRuby.
levels, i.e., the number of instantiation steps to reach the           DeepRuby implements DDI at two layers, the clabject
                                                                           1    module Social
                                                     Module                2      class Person
                                                                           3        attr_accessor(:age)
                    eigenclass
                                                 attr_accessor()           4        def initialize(a)
                    superclass                                             5          self.class.incCounter
                                                                           6          @age = a; end
                      class                           Class                7      end
                                                                           8      class << Person
                                                                           9        def counter; @counter; end
                                                                          10        def incCounter
                                   BasicObject    #BasicObject            11          if @counter.nil?; @counter = 0; end
                                                                          12          @counter = @counter + 1; end
                                                                          13      end
                                                                          14      class Woman < Person; end
                                       Object                             15      Mary = Woman.new(31)
                                                     #Object              16      Mary.age = 27
                                 instance_
                                   variables()
                                                                          17      puts Mary.age         # => 27
                                 inspect2()                               18      puts Person.counter # => nil
                                                                          19      puts Woman.counter    # => 1
                                                                          20      class << Mary
                                                                          21        attr_accessor(:name)
                                       Person                             22      end
                                                     #Person
                                                                          23      Mary.name = "Maria"
                                 age()
                                 age=()          counter()                24    end
                                 initialize()    incCounter()             25    class Object
                                                                          26      def inspect2
                                                                          27        str = "(#{self}"
                                      Woman
                                                                          28        instance_variables.each {|x| str = str +
                                                    #Woman                29           " #{x}=#{instance_variable_get(x)}"}
                                 @counter = 1
                                                                          30        str += ")"; end
                                                                          31    end
                                                                          32    puts Social::Person.inspect2
                                       #Mary                              33    # => (Social::Person)
                Mary:Woman
                                                                          34    puts Social::Woman.inspect2
               @age = 27
                                 name()                                   35    # => (Social::Woman @counter=1)
               @name =„Maria“
                                 name=()
                                                                          36    puts Social::Mary.inspect2
                                                                          37    # => (# @age=27 @name="Maria")

Fig. 1. Introductory example to Ruby’s object model: Ruby code and custom graphical representation of Ruby objects. Predefined objects depicted in grey



layer and the clabject facet layer. DeepRuby’s clabject facet                  a small but intricate example (see Fig. 1).
layer makes explicit each of the otherwise implicit facets                        Ruby’s modules provide a namespacing mechanism for
of a DDI clabject by a flat Ruby object. For example,                          constants, such as class names. Class Person (see line 1:2,
clabject facet CarModelˆ(2,1) with property owner=Person                       that is line 2 in the listing in Fig. 1) is created within
represents the instance-instance-type of CarModel. Clabject                    module Social and can be accessed outside the module by
facet CarModelˆ(0,1) with property creator=Person represents                   qualified name Social::Person (line 1:32). Note: method
the self-type of CarModel. CarModelˆ(0,0) with property                        puts writes a string representation of the given object to an
creator=Peter represents the self-value of CarModel. Clabject                  IO stream – for illustration, the actual output of the Ruby
facet CarModelˆ(2,2) with property engine=EngineModel rep-                     program is given in the program as a comment (e.g., # =>
resents the instance-instance-metatype of CarModel. Clabject                   (Social::Person)).
facet CarModelˆ(1,1) with property listPrice=CurrencyValue                        Member attributes of a Ruby class are defined as getter
represents the instance-type of CarModel.                                      and setter methods that access instance variables. Instance
   In the remainder of the paper, we give, in Sect. II, an                     variables are created when set by a method. To avoid the need
introduction to Ruby’s object model. In Sect. III, we introduce                to write getters and setters by hand, class Module provides
a more intricate example DDI model and its representation                      a method attr_accessor that creates getter and setter
in DeepRuby. We also explain the clabject naming scheme                        methods for an attribute of a given name. For example, in line
typically used with DDI for clabjects with more than two                       1:3, class Person (an instance of Class which inherits from
instantiation levels. Sect. IV explains the clabject facet layer.              class Module) calls attr_accessor for symbol :age to
Sect. V exemplifies the extension of clabject facets with                      create setter method age= and getter method age in class
custom methods. Sect. VI gives an overview of related work.                    Person to write and read instance variables @age (names
Sect. VII concludes the paper with ongoing and future work re-                 of instance variables are marked by prefix ‘@’) of instances of
garding the implementation of advanced constructs of DDI [9]                   class Person, such as Mary (see line 1:16 and line 1:17).
and Dual Deep Modeling [11].                                                      In Ruby, classes are treated as objects and can have instance
                                                                               variables themselves, called class instance variables. Classes
        II. BACKGROUND : RUBY ’ S O BJECT M ODEL
                                                                               are instances of class Class and also may have an eigenclass
  As a background for forthcoming sections this section                        (also referred to as singleton class). Methods defined with
explains some relevant aspects of Ruby’s object model along                    a class’s eigenclass (also referred to as singleton methods
 1   module SalesMgmt
 2       p = DDI::Model.new(SalesMgmt,3)                                                                          Product3
 3       DDI::Clabject.new(p,1,:Person)                                                                  categoryMgr1-1 = Person
 4       Person.new(:MsBlack)                                                                            owner3-1 = Person
 5       Person.new(:Peter)
 6       Peter.define(:spouse,0,1,Person)
                                                                                  Category
 7       Peter.ˆ(0,0).spouse = MsBlack                                                                 Car2
                                                                                                                                   Bike2
 8       DDI::Clabject.new(p,2,:CarEngine)                                                     categoryMgr0-0
 9       CarEngine.new(:EngineK5)                                                                  = MsBlack                categoryMgr0-0
                                                                                               engine2-2                        = MsBlack
10       EngineK5.new(:Engine123)
                                                                                                   = CarEngine
11       DDI::Clabject.new(p,3,:Product)
12       Product.define(:categoryMgr, 1, 1, Person)
13          .define(:owner, 3, 1, Person)                                         Model             BMW Z41                   BromptonM6L1
14       Product.new(:Bike)                                                                    engine1-1 = EngineK5
15       Bike.new(:BromptonM6L)
16       Bike.ˆ(0,0).categoryMgr = MsBlack
17       BromptonM6L.new(:PetersBike)                                             Individual       PetersCar0
                                                                                                                                PetersBike0
18       PetersBike.ˆ(0,0).owner = Peter                                                       owner0-0 = Peter
                                                                                               engine0-0=Engine123          owner0-0 = Peter
19       Product.new(:Car)
20       Car.define(:engine, 2, 2, CarEngine)
21       Car.categoryMgr = MsBlack
22       Car.new(:BMWZ4)
23       BMWZ4.ˆ(1,1).engine = EngineK5                                                                            Person1
24       BMWZ4.new(:PetersCar)                                                                           favouriteItem1-3 = Product
25       PetersCar.ˆ(0,0).owner = Peter
26       PetersCar.ˆ(0,0).engine = Engine123
27       Person.define(:favouriteItem, 1, 3, Product)                             Individual
28       Peter.ˆ(0,0).favouriteItem = PetersCar                                                                               MsBlack0
29       MsBlack.ˆ(0,1).favouriteItem = BromptonM6L                                                                  favouriteItem0-1 =
30       puts Peter.favouriteItem.name                                                                                           BromptonM6L
31       # => PetersCar
                                                                                                         Peter0
32       puts PetersCar.ˆ(0,1).engine.name
                                                                                               favouriteItem0-0 =
33       # => EngineK5                                                                                          PetersCar
34       Product.getMembersN(2).each{|c| puts c.name }                                         spouse0-1 = Person
35       # => BromptonM6L \n BMWZ4                                                             spouse0-0 = MsBlack
36   end

                              Fig. 2. Running example: A DeepRuby program (left) realizing a DDI model (right)



or class methods) can be used to access a class’s class                the direct or indirect superclass of all custom classes created
instance variables. The eigenclass of a class has as super-            in Ruby programs and also the superclass of class Module
class the eigenclass of the class’s superclass. For example,           and Class. A method added to class Object can thus be
Person’s eigenclass (labelled #Person in the graphical                 called from any Ruby object (with Ruby classes being also
representation) is opened by ‘class << Person’ at line                 Ruby objects). Method inspect2 (line 1:26) is defined with
1:8. Person’s eigenclass defines a getter method counter               class Object; when invoked on an object, it creates a string
(line 1:9) together with a method incCounter (line 1:10)               consisting of the object’s name and its instance variables (see
which is called (line 1:5) to increment the counter every              lines 1:32–1:36).
time a new object is created. Class Woman has superclass
                                                                        III. D UAL D EEP I NSTANTIATION IN RUBY – AN E XAMPLE
Person (defined by ‘class Woman < Person’ at line
1:14) and, thus, #Woman (the eigenclass of Woman) has                     In this section DeepRuby is explained along the example
superclass #Person (the eigenclass of Person).                         depicted and implemented in Fig. 2. Ruby’s modules are used
   Class instance variables really belong to the class (as an          as namespacing mechanism. The clabjects of a DDI model
object) and class methods are called in the context of a class         are created within such a module/namespace. For example,
object. For example, when calling Woman.new to create a                module SalesMgmt (line 2:1) serves as namespace for a DDI
new instance of class Woman the initializer defined with class         model with depth 3 (line 2:2), i.e., a model with maximum
Person (line 1:4) is called, incCounter is called in the               source and target potencies of 3.
context of class Woman setting instance variable @counter              Creating clabject hierarchies. A DDI model consists of one
of Woman to 1 (see comment in line 1:19) and not of Person             or more clabject hierarchies. Every clabject hierarchy has one
which remains undefined (see comment in line 1:18).                    root clabject. A root clabject has a fixed clabject potency
   Single objects may also have singleton classes with single-         (specifying the number of instantiation levels beneath the root)
ton methods. For example, Mary’s singleton class (opened at            and typically has a name. For example, clabject Person (line
line 1:20 by class << Mary and depicted as #Mary) de-                  2:3) and clabject Product (line 2:11) are the root clabjects
fines getter and setter methods for accessing instance variable        in the SalesMgmt model and have a potency of 1 and 3,
@name of Mary.                                                         respectively.
   Ruby allows to open existing classes to add additional                 Clabjects are instantiated by sending message new. The
methods which then affect all direct and indirect instances of         new clabject is in the same module as its class and has a
the class. For example, class Object (opened at line 1:25) is          potency 1 lower than its class. For example, clabject Person
with potency 1 is instantiated by MsBlack (line 2:4) and by         target potency 3, meaning that the range of favouriteItem
Peter (line 2:5), which get potency 0. Clabject Product             is given by the members of the members of the members of
with potency 3 is instantiated by Bike (line 2:14) and by           clabject Product.
Car (line 2:19) which get potency 2.                                Querying clabject hierarchies and attributes. The values
Naming clabjects. The names of clabjects in DDI models              and (meta) types of a clabject’s attributes are queried by
(such as in Fig. 2) may seem counter-intuitive. For example,        sending the attribute name to the clabject facet which is
one would typically consider a class named Car to be a              identified by the clabject together with source potency and
specialization (and not an instantiation) of class Product.         target potency. For example, sending attribute name engine
In the following we explain how to read such models and             to PetersCar’s clabject facet with source potency 0 and tar-
sketch the rationale behind this naming scheme.                     get potency 1 (line 2:32) returns the type of engine of
   It is sometimes argued that deep instantiation’s support for     PetersCar, which is EngineK5, which is inherited from
concise modeling comes with the price of lack of concep-            BMWZ4.
tual clarity [3]: one clabject may represent multiple domain           For getting or setting attributes with source potency 0 and
concepts which makes it more difficult to differentiate these       target potency 0 it is not necessary to specify the clabject facet.
different domain concepts. In order to make these different         If a message is sent to a clabject it dispatches it to its 0-0 facet.
domain concepts explicit, we proposed [9]–[11] to give mean-        For example, when sending attribute name favouriteItem
ingful names to instantiation levels of a clabject and to produce   to Peter (line 2:30) it is dispatched to Peterˆ(0,0) and
the name of an implicitly represented domain concept by             retrieves Peter’s favourite item, which is his car.
combining a clabject name with a level name.                           DeepRuby provides methods to navigate clabject hierarchies
   For example (see Fig. 2), clabject Product has instantia-        to facilitate flexible querying of DDI models. For example,
tion levels Category, Model, and Individual, representing do-       line 2:34 retrieves the members of the members of Product,
main concepts Product Category, Product Model, and Product          these are BMWZ4 and Brompton.
Individual. Clabject Car is an instance of Product Category         DeepRuby provides (1) generic query mechanisms (1a) to
and further represents domain concepts Car Model and Car            retrieve attribute values and (meta) types including inherited
Individual (which are specializations of Product Model and          values and types (1b) to navigate clabject hierarchies and
Product Individual). Clabject BMWZ4 is an instance of Car           retrieve a clabject’s members at a specific level and (2) takes
Model and further represents domain concept BMWZ4 Individ-          care of keeping DDI models consistent when defining and
ual (a specialization of Car Individual). Finally, Peters Car       setting attributes, with regard to: (2a) correct number of
is an instance of BMWZ4 Individual.                                 instantiation steps at the source and the target, (2b) target
                                                                    clabjects are compatible with targets at higher potencies, (2c)
Defining and instantiating attributes. Attributes are defined
                                                                    a newly introduced target does not produce type conflicts at
with a source clabject, a name, a source potency, a target
                                                                    lower potencies and at descending clabjects.
potency, and a target clabject. For example, clabject Product
defines an attribute with name owner, source potency 3, target                    IV. D EEP RUBY UNDER THE H OOD
potency 1, and target clabject Person (line 2:13).                     By freely combining source and target potencies, a clabject
   A clabject has many clabject facets, one for each com-           c with maximum source potency m (given by the clabject’s
bination of source potency and target potency. In order to          potency) and maximum target potency n (given by the DDI
set attribute engine at source potency 1 and target po-             model’s depth) has (m + 1) × (n + 1) clabject facets. Every
tency 1 at clabject BMWZ4 to EngineK5, one first selects            such facet corresponds to a combination of source potency and
the clabject facet (BMWZ4.ˆ(1,1)) to which one sends                target potency. The basic idea of DeepRuby is to represent
engine=EngineK5 (line 2:23).                                        every such clabject facet as a ’flat’ Ruby object (which in
   Clabjects with potency 0 have no members, yet they may           the current approach is always a class) with instance variables
define attributes with a target potency higher than 0, similar to   and methods. For example, clabject Car with potency 2 in a
what can be accomplished in Ruby with singleton classes of          model with depth 3 has 12 (3 × 4) clabject facets. The object
an object (e.g., attribute name defined with Mary’s singleton       Carˆ(0-0) holds @catMgr=MsBlack and Carˆ(2-2)
class at line 21 in Fig. 1). For example, clabject Peter defines    holds @engine=CarEngine as instance variable. The rela-
an attribute spouse with source potency 0, target potency 1,        tionships between clabject facets are represented using Ruby
and target Person (line 2:6) and instantiates it with target        constructs:
potency 0 and target MsBlack (line 2:7).                                                                           i,j
                                                                       • The eigenclass of clabject facet c            is clabject
                                                                                 i,(j+1)
   Root clabjects with clabject potency 1 are akin to ‘normal’           facet c         . For example, the eigenclass of class
classes in that they have individuals as members. They are               Carˆ(0,0) is clabject facet Carˆ(0,1).
different from normal classes in that their attributes may have        • If clabject c is an instantiation of clabject d, then
a range defined at a higher classification level. For example,           every clabject facet ci,j has clabject facet d(i+1),j
Person (line 2:3) has individuals MsBlack (line 2:4) and                 as superclass. For example, Carˆ(0,0) has super-
Peter (line 2:5) as members, yet it defines an attribute                 class Productˆ(1,0) and Carˆ(0,1) has superclass
favouriteItem (line 2:27) with target Product and                        Productˆ(1,1).
                 eigenclass               superclass                                                        target potency
                                                                                0                       1                            2                   3
                                                             level(0)
                          Product3                Product                 Product^(0,0)         Product^(0,1)                Product^(0,2)         Product^(0,3)     0
               categoryMgr1-1 = Person
               owner3-1 = Person                             level(1)
                                                                          Product^(1,0)         Product^(1,1)                Product^(1,2)         Product^(1,3)
                                                                                                                                                                     1
                                                                                              @catMgr = Person
                                                                                                                           catMgr()




                                                                                                                                                                         source potency
                                                                                              catMgr();catMgr=()           catMgr=()

                                                             level(2)
                                                                          Product^(2,0)         Product^(2,1)                Product^(2,2)         Product^(2,3)
                                                                                                                                                                     2


                                                             level(3)
                                                                          Product^(3,0)         Product^(3,1)                Product^(3,2)         Product^(3,3)     3
                                                                                              @owner = Person
                                                                                              owner()                      owner()
                                                                                              owner=()                     owner=()


                                              instantiation_of              superclass            superclass                     superclass         superclass

                                                             level(0)
                            Car2                       Car                  Car^(0,0)             Car^(0,1)                      Car^(0,2)           Car^(0,3)
               categoryMgr0-0 = MsBlack                                 @catMgr = MsBlack
               engine2-2 = CarEngine


                                                             level(1)
                                                                            Car^(1,0)             Car^(1,1)                      Car^(1,2)           Car^(1,3)



                                                             level(2)
                                                                            Car^(2,0)             Car^(2,1)                      Car^(2,2)           Car^(2,3)
                                                                                                                           @engine = CarEngine
                                                                                              engine()                                           engine()
                                                                                              engine=()                    engine()              engine=()
                                                                                                                           engine=()

                                              instantiation_of                superclass            superclass
                                                                                                                                   superclass         superclass

                                   1
                                                             level(0)
                          BMW Z4                  BMWZ4                   BMWZ4^(0,0)           BMWZ4^(0,1)                  BMWZ4^(0,2)           BMWZ4^(0,3)
               engine1-1 = EngineK5

                                                             level(1)
                                                                          BMWZ4^(1,0)           BMWZ4^(1,1)                  BMWZ4^(1,2)           BMWZ4^(1,3)
                                                                                              @engine = EngineK5



                                              instantiation_of                  superclass              superclass                  superclass          superclass


                                                             level(0)
                      PetersCar0                 PetersCar               PetersCar^(0,0)       PetersCar^(0,1)              PetersCar^(0,2)       PetersCar^(0,3)
                    0-0
               owner = Peter                                            @owner = Peter
               engine0-0 =Engine123                                     @engine = Engine123

                                                 DeepRuby                                                      DeepRuby
                          DDI Model
                                                Clabject Layer                                            Clabject Facet Layer


                                          Fig. 3. Realizing clabject facet matrices in Ruby using superclass and eigenclass



   A clabject is first represented as an instance of class                                         by BMWZ4ˆ(1,1) and in turn by PetersCarˆ(0,1).
Clabject (line A:25 in the Appendix) with an array                                                 Target clabjects of attributes (represented as instance
                                                                                                    •
levels which holds for each source potency a reference                                             variables) are inherited from superclass ci+1,j to sublass
to the respective instance of class ClabjectFacet (see                                             ci,j (this is implemented generically as part of Deep-
line A:210) with target potency 0, from there one can navigate                                     Ruby). For example, when sending message engine
to other clabject facets along eigenclass relationships. Sending                                   to PetersCarˆ(0,1) one gets EngineK5, which is
message ˆ(i,j) to a clabject c returns clabject facet ci,j .                                       inherited from BMWZ4ˆ(1,1).
A clabject facet’s attribute clabject (line A:213) allows                                          What is the role of eigenclass relationships in Deep-
to navigate back from clabject facet to clabject; for example,                                 Ruby?:
from clabject facet Carˆ(2,1) to clabject Car.                                                   • The eigenclass c
                                                                                                                      i,j+1
                                                                                                                              of a clabject facet ci,j pro-
     What is the role of superclass relationships in Deep-                                         vides methods for accessing instance variables of
Ruby?:                                                                                             ci,j (this comes for free with the eigenclass con-
                                                i+1,j
   • Methods are inherited from superclass d          to subclass                                  struct). For example, setter method catMgr= de-
      i,j
     c (this comes for free, since this is what class hier-                                        fined in Productˆ(1,2) is called for setting
     archies are traditionally used for). For example, setter                                      @catMgr=Person in Productˆ(1,1)
     method engine= defined at Carˆ(2,1) is inherited                                            • Target clabjects (represented as instance variables) at
     ci,j+1 act as constraint for target clabjects at ci,j          Currency.ˆ(1,1)) (see line 4:4). Second-level mem-
     (this is implemented generically as part of DeepRuby).         bers of Currency get getter and setter for attribute
     For example, target clabject engine=EngineK5 of                value by invoking attr_accessor on the eigenclass of
     PetersCarˆ(0,1) (inherited from BMWZ4ˆ(1,1))                   Currency.ˆ(2,0) (which is Currency.ˆ(2,1)) (line
     acts as constraint when invoking setter method engine=         4:7). Currencies Pound, Euro, and Yen are created with
     on PetersCarˆ(0,0).                                            their isocode and exchange rate (lines 4:20–4:25). GBP38200
   We have further been experimenting with two alternative          is an instantiation of Pound (and a second-level member of
representation of the clabject facet matrix: In the first alter-    Currency) with value 38200 (line 4:26).
native represenation, clabject facets with target potency 0 are        Second-level members of Currency have a method
represented as simple objects and not as classes. This would        for pretty printing (defined with the eigenclass of
also be a reasonable design choice since these facets do not        Currency.ˆ(2,0) which is Currency.ˆ(2,1)), mak-
act as classes, yet it makes the implementation a bit more          ing use of value and isocode. In order to get the
complex.                                                            isocode the method needs to first navigate from the clabject
   In the second alternative representation, we introduce an        facet (instance of ClabjectFacet) to the corresponding
additional layer between DDI-clabject layer and clabject facet      clabject (instance of Clabject) along attribute clabject
layer in order to align DeepRuby with DeepTelos [6]. At this        and from there along attribute cclass to the corresponding
intermediate layer, a DDI clabject is represented by multiple       first-level member of Currency (line 4:9). Sending pretty
simple clabjects. A simple clabject resembles an object, class,     to GBP38200 results in ‘GBP 38200’ (line 4:27).
metaclass, or metaˆn class in DeepTelos. Clabject facets with          Second-level members of Currency further have a
the same difference between source potency and target potency       method toCurrency which takes a first-level member of
are collected into such a simple clabject. For example, clabject    Currency as parameter (line 4:11). Sending toCurrency
facets Carˆ(0,0), Carˆ(1,1), Carˆ(2,2) are collected                with parameter Euro to GBP38200 produces a new instanti-
into a simple clabject Car 0 and clabject facets Carˆ(1,0),         ation of Euro which is pretty printed as ‘EUR 42784.0’ (line
Carˆ(2,1) are collected into a simple clabject Car 1, with          4:28).
Car 0 having class Car 1 as its most-general instance. A               The      eigenclass    of   Yen.ˆ(1,0)         (which   is
simple clabject combining facets where the target potency           Yen.ˆ(1,1)) overwrites method pretty inherited
is higher than the source potency (e.g., Productˆ(0,1),             from Currency.ˆ(2,1)) to use unicode symbol U instead
Productˆ(1,2), Productˆ(2,3)) cannot be directly                    of isocode JPY . The new instantiation of Yen created by
represented in DeepTelos.                                           sending toCurrency with parameter Yen to GBP38200 is
   In this section we have explained the basic principles of        pretty printed as ‘U 5556363.64’ (line 4:33).
DeepRuby’s implementation and use of Ruby’s eigenclass                 Clabjects UK and Japan instantiate Country and have
construct to implement Dual Deep Instantiation and have             local currencies Pound and Yen, respectively. Asking for
sketched two alternative representations. The evaluation and        the exchange rate of Japan’s local currency returns 0.0077
fine-tuning of these alternatives is subject to ongoing work.       (line 4:39).
                                                                       Method priceInCountry (see line 4:42) of second-
   V. S IMPLE ATTRIBUTES AND C USTOM M ETHODS IN                    level members of Product takes a country as parameter
                     D EEP RUBY                                     and converts the listPrice of second-level instantiations
                                                                    of Product to the country’s local currency, returning a new
   Using classes/eigenclasses arranged in superclass hierar-        instantiation of the given currency with the value being the
chies for realizing the clabject facet matrix allows to use stan-   result of the conversion. Sending priceInCountry with
dard Ruby constructs to implement simple attributes (attributes     parameter Japan to BMWZ4 (see line 4:48) returns a new
with non-clabjects as range) and behavior (custom methods)          clabject pretty-printed as ‘U 5556363.64’ (line 4:48).
on top of the clabject facet matrix, and to specialize behavior
(i.e., overwrite methods, add additional methods) along the                            VI. R ELATED W ORK
clabject hierarchy.                                                    With the advent of multi-level modeling, the question of
   To demonstrate these features, the running example from          multi-level model execution emerges. Melanee [1], DeepTe-
Fig. 2 is extended in Fig. 4 with clabject hierarchies              los [6], MetaDepth [8], DeepJava [7], and XModeler [4] are
Currency with simple attributes for exchange rate (with             modeling tools and frameworks that support model execution,
Euro as reference currency), isocode and value, and Country         each pursuing a different strategy with respect to supporting
with a local currency. Clabject Product is extended with a          model execution. Multilevel programming may also be real-
listPrice and a method priceInCountry to convert                    ized in a type-safe manner by metaprogramming and reflective
the list price to the local currency of the given country.          constraints [5].
   First-level members of Currency receive getters and                 The Melanee multi-level modeling tool [1] supports model
setters for simple attributes exchRate and isocode                  execution through a service API and a plug-in mechanism. The
by invoking standard Ruby method attr_accessor                      communication between modeling and execution environment
on the eigenclass of Currency.ˆ(1,0) (which is                      can be realized using socket-based communication. Changes
 1   module SalesMgmt
 2     DDI::Clabject.new(Product.model,2,:Currency)
 3     class << Currency.ˆ(1,0)
 4       attr_accessor(:isocode, :exchRate)
 5     end                                                                                                  Currency2
 6     class << Currency.ˆ(2,0)
                                                                                              value2
 7       attr_accessor(:value)                                                                exchRate1
 8       def pretty                                                                           isoCode1
 9         "#{clabject.cclass.isocode} #{value}"                                              pretty2()
10       end                                                                                  toCurrency2(Currency1) : Currency2
11       def toCurrency(c)
12         raise "#{c} is not a currency" \
13              unless (c.isMemberN(1,Currency))
14         obj = c.new                                                                   Euro1              Pound1                 Yen1
15         obj.value = (value * clabject.cclass                                     exchRate = 1        exchRate = 1.12    exchRate = 0.0077
16              .exchRate / c.exchRate).round(2)                                    isocode = „EUR“     isocode = „GBP“    isocode = „JPY“
17         return obj                                                                                                      pretty1-0()
18       end
19     end
20     Currency.new(:Pound);                                                                              GBP382000
21     Pound.isocode = "GBP"; Pound.exchRate = 1.12;                                value= 42784.0                         value= 5556363.64
                                                                                                        value = 38200
22     Currency.new(:Euro)
23     Euro.isocode = "EUR"; Euro.exchRate = 1
24     Currency.new(:Yen)
25     Yen.isocode = "JPY"; Yen.exchRate = 0.0077                                                            Country1
26     Pound.new(:GBP38200); GBP38200.value = 38200
                                                                                                 localCurrency1-1 = Currency
27     puts GBP38200.pretty # => GBP 38200
28     puts GBP38200.toCurrency(Euro).pretty
29     # => EUR 42784.0
30     class << Yen.ˆ(1,0)                                                                    UK0                               Japan0
31       def pretty; "\u00A5 #{value}"; end                                         localCurrency0-0 = Pound          localCurrency0-0 = Yen
32     end
33     puts GBP38200.toCurrency(Yen).pretty
34     # => U 5556363.64
35     DDI::Clabject.new(Product.model,1,:Country)                                                           Product3
36     Country.define(:localCurrency,1,1,Currency)                                         listPrice2-2 = Currency
37     Country.new(:UK).localCurrency = Pound
38     Country.new(:Japan).localCurrency = Yen                                             priceInCountry2(Country1) : Currency2
39     puts Japan.localCurrency.exchRate #=> 0.0077
40     Product.define(:listPrice, 2, 2, Currency)
41     class << Product.ˆ(2,0)                                                                                 Car2
42       def priceInCountry(country)
43         listPrice.toCurrency(country.localCurrency)
                                                                                                             BMW Z41
44       end
45     end                                                                                            listPrice0-0 = GBP38200
46     BMWZ4.ˆ(0,0).listPrice = GBP38200
47     puts BMWZ4.priceInCountry(Japan).pretty
48     # => U 5556363.64
49   end

                         Fig. 4. Custom methods: DeepRuby program (left) realizing a DDI model with methods (right)



in the modeling environment then automatically reflect in the          but comes with powerful metamodeling features unmatched
execution environment, and vice versa. The execution envi-             by DeepRuby.
ronment can be implemented as a Java program. Concerning                  MetaDepth [8] is a text-based multi-level modeling frame-
the definition of execution semantics, different approaches            work with potency-based deep instantiation. MetaDepth is a
exist. A “pragmatic” approach, for example, employs a Java             Java-based implementation using a custom syntax. Among the
representation of the multi-level model where each clabject in         primary features of MetaDepth are multi-level constraints and
the multi-level model corresponds to a single Java class, with         derived attributes at different meta-levels. Execution semantics
execution semantics defined using plain Java code.                     is defined using an OCL extension. MetaDepth provides an
   DeepTelos [6] extends the Telos metamodeling language               interpreter for the thus defined multi-level models. MetaDepth
and its implementation with “most general instances” to add            also supports code generation complying to the Java Metadata
support for deep instantiation. Since DeepTelos defines the            Interface.
extensions as a set of Datalog axioms, DeepTelos models are               DeepJava [7] is an extension of the Java programming
compatible with ConceptBase, an implementation of a Telos              language with a mechanism for potency-based deep instan-
variant. ConceptBase also allows for the definition of exe-            tiation. Internally, a compiler transforms DeepJava code into
cutable models using event-condition-action rules. In Sect. IV         plain Java. Hence, each DeepJava class translates into a set
we sketched how to group clabject facets into simple clabjects         of Java classes, one for each clabject facet. The compiler also
that resemble DeepTelos classes. DeepTelos does not directly           generates code for clabject instantiation at runtime, which is
support self-describing clabjects (i.e., clabject with attributes      realized using Java’s reflective functions. Clabject instantiation
where the target potency is higher than the source potency)            results in the dynamic generation of a number of interfaces.
As a limitation, direct access without getters and setters is                      [8] de Lara, J., Guerra, E.: Deep meta-modelling with MetaDepth. In: Vitek,
restricted to attributes with potency values smaller than two.                         J. (ed.) TOOLS 2010. LNCS, vol. 6141, pp. 1–20. Springer (2010)
                                                                                   [9] Neumayr, B., Jeusfeld, M.A., Schrefl, M., Schütz, C.: Dual deep instan-
With respect to Java, Ruby’s eigenclass concept much better                            tiation and its conceptbase implementation. In: Jarke, M., Mylopoulos,
suits the clabject philosophy of multi-level modeling. As                              J., Quix, C., Rolland, C., Manolopoulos, Y., Mouratidis, H., Horkoff,
opposed to DeepJava, DeepRuby supports deep instantiation                              J. (eds.) CAiSE. Lecture Notes in Computer Science, vol. 8484, pp.
                                                                                       503–517. Springer (2014)
with both a source and a target potency, resulting in the                         [10] Neumayr, B., Schuetz, C.G.: Multilevel modeling. In: Liu, L., Özsu,
generation of a matrix of Ruby classes for each clabject.                              M.T. (eds.) Encyclopedia of Database Systems. pp. 1–8. Springer New
                                                                                       York, New York, NY (2017)
                          VII. C ONCLUSION                                        [11] Neumayr, B., Schuetz, C.G., Jeusfeld, M.A., Schrefl, M.: Dual deep
                                                                                       modeling: multi-level modeling with dual potencies and its formalization
   In this paper we introduced DeepRuby, a Ruby implemen-                              in F-Logic. Software & Systems Modeling pp. 1–36 (2016)
tation of the core language constructs of Dual Deep Instantia-                    [12] Perrotta, P.: Metaprogramming Ruby 2. The Pragmatic Programmers
                                                                                       (2014)
tion [9]: clabject hierarchies and attributes with dual potencies.
The system takes care of consistent instantiation of clabjects                                                       A PPENDIX
and attributes and provides methods for querying multi-level                                          D EEP RUBY I MPLEMENTATION
models. Our experiences with implementing DeepRuby have
                                                                                    1   module DDI
confirmed our initial conjecture that a dynamic programming                         2
                                                                                    3   class Model
language like Ruby that does not strictly separate classes and                      4     attr_reader(
                                                                                    5       :depth, # maximum potency of user clabjects
objects is a good platform for implementing clabject-based                          6       :modul, # module/namespace for clabjects
                                                                                    7     )
modeling constructs.                                                                8     def initialize(mod, n)
                                                                                    9       raise "initial maximum-depth too low (n < 1)" if n < 1
   In an internal prototype we have also implemented DDI’s                         10       @modul = mod
                                                                                   11       @depth = n
advanced modeling constructs (which are missing from the                           12       # create module-specific ClabjectLevel-class
                                                                                   13       # because of different eigenclass depth
DeepRuby version presented in this paper): multi-valued prop-                      14       cls = Class.new
                                                                                   15       modul.const_set(:ClabjectLevel, cls)
erties, bi-directional properties, and clabject generalization.                    16       # include module ClabjectFacet in eigenclasses
                                                                                   17       for n in (0..depth)
The fine-tuning of the advanced prototype and experimentation                      18         cls = cls.singleton_class
                                                                                   19         cls.send(:include, ClabjectFacet)
with alternative representations of the clabject facet matrix is                   20       end
                                                                                   21     end
subject to ongoing work.                                                           22   end # end Model
                                                                                   23
   Dual deep modeling (DDM) [11], an extended version                              24
                                                                                   25   class Clabject
of DDI, additionally comes with multi-level cardinality con-                       26     attr_reader(
                                                                                   27       :model,    # reference to DDI model
straints, property specialization hierarchies, and distinguishes                   28       :levels, # array of clabject levels
                                                                                   29       :name,
between property value and property range. Implementing                            30       :instantiations,    # first-level members
                                                                                   31       :instantiation_of, # class clabject
these constructs in DeepRuby is subject to future work.                            32       :potency
                                                                                   33     )
   Moving beyond previous implementations of DDI/DDM in                            34
                                                                                   35     def cclass
ConceptBase [9] and F-Logic [11], DeepRuby allows to extend                        36       instantiation_of
                                                                                   37     end
clabject facets with custom methods. We have exemplified                           38
                                                                                   39     def members
the implementation of such methods and their inheritance and                       40       instantiations
                                                                                   41     end
specialization along the clabject facet hierarchy.                                 42
                                                                                   43     def ˆ(srcPtcy,tgtPtcy)
                                                                                   44       facet(srcPtcy,tgtPtcy)
                              R EFERENCES                                          45     end
                                                                                   46
                                                                                   47     def facet(srcPtcy,tgtPtcy)
 [1] Atkinson, C., Gerbig, R., Metzger, N.: On the execution of deep models.       48       raise "Target potency #{tgtPtcy} above max potency #{model.depth}+1."
     In: Mayerhofer, T., Langer, P., Seidewitz, E., Gray, J. (eds.) Proceedings                if tgtPtcy > (model.depth+1)
                                                                                   49       return levels[srcPtcy].eigenclassN(tgtPtcy)
     of the 1st International Workshop on Executable Modeling. CEUR                50     end
     Workshop Proceedings, vol. 1560, pp. 28–33. CEUR-WS.org (2015)                51
                                                                                   52     def initialize(model, potency, name=nil, parent=nil)
 [2] Atkinson, C., Kühne, T.: The Essence of Multilevel Metamodeling. In:         53       @name = name
     Gogolla, M., Kobryn, C. (eds.) Proceedings of the 4th International           54       @instantiation_of = parent
                                                                                   55       @potency = potency
     Conference on the UML 2001, Toronto, Canada. LNCS, vol. 2185, pp.             56       @model = model
     19–33. Springer Verlag (Oct 2001)                                             57       @levels = Array.new(potency+1)
                                                                                   58       for m in (0..potency)
 [3] Carvalho, V.A., Almeida, J.P.A.: Toward a well-founded theory for             59         if parent.nil?
     multi-level conceptual modeling. Software & Systems Modeling (2016)           60           @levels[m] = createClabjectLevel(model
                                                                                   61              .modul.const_get(:ClabjectLevel), m)
 [4] Clark, T., Gonzalez-Perez, C., Henderson-Sellers, B.: A foundation for        62         else
     multi-level modelling. In: MULTI 2014. CEUR Workshop Proceedings,             63           @levels[m] = createClabjectLevel(parent
                                                                                   64              .levels[m+1], m)
     vol. 1286, pp. 43–52. CEUR-WS.org (2014)                                      65         end
 [5] Draheim, D.: Reflective constraint writing - A symbolic viewpoint of          66       end
                                                                                   67       @instantiations = Array.new
     modeling languages. Trans. Large-Scale Data- and Knowledge-Centered           68       model.modul.const_set(name, self) if name
     Systems 24, 1–60 (2016)                                                       69       return self
                                                                                   70     end
 [6] Jeusfeld, M.A., Neumayr, B.: DeepTelos: Multi-level modeling with             71
     most general instances. In: Comyn-Wattiau, I., Tanaka, K., Song, I.,          72     def new(name=nil)
                                                                                   73       obj = Clabject.new(
     Yamamoto, S., Saeki, M. (eds.) ER 2016. LNCS, vol. 9974, pp. 198–             74         self.model, self.potency-1, name, self)
     211. Springer (2016)                                                          75       instantiations << obj
                                                                                   76       return obj
 [7] Kuehne, T., Schreiber, D.: Can programming be liberated from the two-         77     end
     level style: Multi-level programming with DeepJava. In: Proceedings           78
                                                                                   79
     of the 22nd Annual ACM SIGPLAN Conference on Object-oriented                  80     def createClabjectLevel(supercls,levelNr)
     Programming Systems and Applications. pp. 229–244 (2007)                      81       cls = Class.new(supercls)
 82     facet = cls                                                             189      facet(srcPtcy,tgtPtcy).send("#{attribute}=", value)
 83     for n in (0..model.depth)                                               190      return self
 84       facet.clabject = self                                                 191    end
 85       facet.tgtPtcy = n                                                     192
 86       facet.srcPtcy = levelNr                                               193    def get(attribute, srcPtcy, tgtPtcy)
 87       if(n < model.depth)                                                   194      facet(srcPtcy,tgtPtcy).send(attribute)
 88         facet = facet.singleton_class                                       195    end
 89       end                                                                   196
 90     end                                                                     197    def getValueSettingObject(attribute, srcPtcy, tgtPtcy)
 91     return cls                                                              198      facet(srcPtcy,tgtPtcy)
 92   end                                                                       199        .getValueSettingObject(attribute.to_s.to_sym)
 93                                                                             200    end
 94   def to_s                                                                  201
 95     name                                                                    202    def getMethodDefiningClass(attribute, srcPtcy, tgtPtcy)
 96   end                                                                       203      facet(srcPtcy,tgtPtcy)
 97                                                                             204        .method("#{attribute.to_sym}").owner
 98   def getMembersN(n)                                                        205    end
 99     if n == 0                                                               206
100       return [self]                                                         207   end # end Clabject
101     elsif n == 1                                                            208
102       return instantiations                                                 209
103     elsif n > 1                                                             210   module ClabjectFacet
104       tempAry = []                                                          211
105       ary = [self]                                                          212    attr_accessor(
106       for m in (1..n)                                                       213      :clabject,
107         ary.each do |cbj|                                                   214      :srcPtcy,
108           tempAry = tempAry + cbj.instantiations                            215      :tgtPtcy
109         end                                                                 216    )
110         ary = tempAry                                                       217
111         tempAry = []                                                        218    def to_s
112       end                                                                   219     clabjectname = (clabject.respond_to?(:name))? clabject.name : clabject
113       return ary                                                            220     "#{clabjectname}ˆ(#{srcPtcy},#{tgtPtcy})"
114     end                                                                     221    end
115   end                                                                       222
116                                                                             223    def parent
117   def isMember(cbj)                                                         224     superclass
118     if self == cbj                                                          225    end
119       true                                                                  226
120     elsif self.respond_to?(:instantiation_of) &&                            227    def eigenclass
            !self.instantiation_of.nil?                                         228     singleton_class
121       self.instantiation_of.isMember(cbj)                                   229    end
122     else                                                                    230
123       false                                                                 231    def inherited(attribute)
124     end                                                                     232     if parent.respond_to?(attribute.to_s.to_sym)
125   end                                                                       233      parent.send(attribute.to_s.to_sym)
126                                                                             234     else
127   def isCompatibleWith(cbj)                                                 235      false
128     return self.isMember(cbj) || cbj.isMember(self)                         236     end
129   end                                                                       237    end
130                                                                             238
131   def isMemberN(n, cbj)                                                     239    def getValueSettingObject(attribute)
132     if n == 0 and self == cbj                                               240     if instance_variable_get("@#{attribute.to_sym}")
133       true                                                                  241      self
134     elsif self.respond_to?(:instantiation_of) &&                            242     else
            !self.instantiation_of.nil?                                         243      getInheritedValueSettingObject(attribute)
135       self.instantiation_of.isMemberN(n-1, cbj)                             244     end
136     else                                                                    245    end
137       false                                                                 246
138     end                                                                     247    def getInheritedValueSettingObject(attribute)
139   end                                                                       248     if parent.respond_to?(attribute.to_s.to_sym)
140                                                                             249      parent.getValueSettingObject(attribute.to_s.to_sym)
141   def method_missing(method, *args)                                         250     else
142     if levels[0].respond_to?("#{method}", *args)                            251      false
143       levels[0].send("#{method}", *args)                                    252     end
144     else                                                                    253    end
145       raise NoMethodError.new("There is no method called #{method} here")   254
146     end                                                                     255    def getMostSpecific(attribute)
147   end                                                                       256     getMostSpecificN(attribute)[:val]
148                                                                             257    end
149   def define(attribute, srcPtcy, tgtPtcy, value)                            258
150     for n in (1..(tgtPtcy+1))                                               259    def getMostSpecificN(attribute)
151       obj = facet(srcPtcy,n)                                                260     if respond_to?(attribute)
152       #crete getter                                                         261      val = self.send(attribute)
153       obj.class_eval("                                                      262        if val
154         def #{attribute}                                                    263          return {:ptcy => 0, :val => val}
155           if @#{attribute}                                                  264        elsif eigenclass.respond_to?(attribute)
156              @#{attribute}                                                  265          x = eigenclass.getMostSpecificN(attribute) #recursion
157           else                                                              266          if x[:val]
158              inherited(’#{attribute}’)                                      267            return {:ptcy => x[:ptcy]+1, :val => x[:val]}
159           end                                                               268          end
160         end"                                                                269        end
161       )                                                                     270      end
162       #create setter                                                        271      return {:val => false}
163       obj.class_eval("                                                      272    end
164         def #{attribute}=(val)                                              273
165           if valueSettingAllowed(:#{attribute}, val)                        274     def valueSettingAllowed(attribute, value)
166              @#{attribute} = val                                            275       if value.kind_of?(Clabject)
167           end                                                               276         ms = getMostSpecificN(attribute)
168         end"                                                                277         if ms[:val] && !value.isMemberN( ms[:ptcy], ms[:val] )
169       )                                                                     278           raise "#{value.name} is not memberN(#{ms[:ptcy]}) of
170     end                                                                                      #{ms[:val].name}"
171     set(attribute, srcPtcy, tgtPtcy, value)                                 279         end
172     return self                                                             280         return true
173   end                                                                       281       else
174                                                                             282         raise "#{value} is no Clabject"
175   def checkDownwardCompatibility(attribute, srcPtcy, tgtPtcy, value)        283       end
176     return true unless levels[srcPtcy].getMostSpecific(attribute)           284     end
177     return true if value.nil?                                               285
178     for potency in (0..srcPtcy)                                             286     def eigenclassN(n)
179       getMembersN(potency).each do |cbj|                                    287       obj = self
180         actMsVal = cbj.levels[srcPtcy-potency]                              288       for m in (1..n) # returns self if n=0
181             .getMostSpecific(attribute)                                     289         obj = obj.singleton_class
182         raise "#{value.name} is not compatible with #{actMsVal.name}" if    290       end
               !value.isCompatibleWith( actMsVal )                              291       return obj
183       end                                                                   292     end
184     end                                                                     293
185   end                                                                       294   end # end ClabjectFacet
186                                                                             295
187   def set(attribute, srcPtcy, tgtPtcy, value, doDownwardCheck = true)       296   end # end module DDI
188     checkDownwardCompatibility(attribute, srcPtcy, tgtPtcy, value) if
           doDownwardCheck