3.4. Modular inheritance

It is possible to inherit all the symbols of a module with the inherit directive. Unlike the open directive, inherited symbols become part of the public interface of a module, as well as it's private interface.

When lookup is performed, entities defined in the module are always considered before inherited ones. This is to ensure a local definition can always be used to resolve an ambiguity, and to ensure that any binding to a local definition cannot be hijacked by a non-local change in another module.

Modular inclusion is transitive because it is specified to include the whole of the public interface of one module in another, including any symbols that module inherits.

Note that as usual and unlike other programming languages, Felix inheritance is fully recursive: a module contains all the symbols it defines plus the transitive closure of all inherited modules.

In particular, it is quite possible for two modules to inherit each other, thereby ensuring they publish the same set of names: note however that local overrides may mean the definition associated with a name is different for each module.

Start felix section to tut/tutorial/tut-2.04-0.flx[1 /1 ]
     1: #line 5176 "./lpsrc/flx_tutorial.pak"
     2: //Check inherit directive
     3: header "#include <iostream>";
     4: header "#include <string>";
     5: 
     6: type int = "int";
     7: type string= "std::string";
     8: proc print:int = "std::cout << $1;";
     9: proc print:string= "std::cout << $1;";
    10: proc endl:1 = "std::cout << std::endl;";
    11: 
    12: module X {
    13:   fun f(a:int):int={ return 11; }
    14: }
    15: module Y {
    16:   fun g(a:int):int={ return 22; }
    17: }
    18: module Z { inherit X; inherit Y; }
    19: 
    20: // check transitivity
    21: module A {
    22:   inherit Z;
    23:   print (f 3); print " "; print (g 5); endl;
    24:   print (Z::f 3); print " "; print (Z::g 5); endl;
    25:   print (A::f 3); print " "; print (A::g 5); endl;
    26: }
    27: 
    28: 
    29: // check recurisve transitive closure
    30: module P { inherit Q; fun ff(a:int):int={return 33;}}
    31: module Q { inherit P; fun gg(a:int):int={return 44;}}
    32: module R {
    33:   inherit P;
    34:   print (ff 1); print " "; print (gg 1); endl;
    35:   print (P::ff 1); print " "; print (P::gg 1); endl;
    36:   print (Q::ff 1); print " "; print (Q::gg 1); endl;
    37:   print (R::ff 1); print " "; print (R::gg 1); endl;
    38: }
    39: 
    40: module W {
    41:   module J { val a:int = 1;}
    42:   inherit J;
    43:   print a; endl;
    44: }
    45: print W::a; endl;
End felix section to tut/tutorial/tut-2.04-0.flx[1]
Start data section to tut/tutorial/tut-2.04-0.expect[1 /1 ]
     1: 11 22
     2: 11 22
     3: 11 22
     4: 33 44
     5: 33 44
     6: 33 44
     7: 33 44
     8: 1
     9: 1
End data section to tut/tutorial/tut-2.04-0.expect[1]