SlideShare una empresa de Scribd logo
1 de 70
Descargar para leer sin conexión
Practical Generative Programming

         Schalk W. Cronjé




                                 ACCU 2006
                            © Schalk W. Cronjé
Even in this new millennium, many engineers will still
build components that have very little reuse potential
due to the inflexible way that they were constructed.

This leads to excessive time required to adapt a
component for usage in another system.




                                                    ACCU 2006
                                               © Schalk W. Cronjé
Welcome to the world of

Generative Programming




                               ACCU 2006
                          © Schalk W. Cronjé
Themes
●   GP 101
●   Building a single system
●   C++ footwork
●   Working with C
●   Working with dynamic languages
●   Building multiple systems
●   Integration & testing




                                          ACCU 2006
                                     © Schalk W. Cronjé
Definition


It is a software engineering paradigm where the aim is
to automatically manufacture highly customised and
optimised     intermediate   or    end-products   from
elementary, reusable components by means of
configuration knowledge.




                                                  ACCU 2006
                                             © Schalk W. Cronjé
Elements of Generative
Programming

                      Configuration
                       Knowledge




Problem space                            Solution space



•Domain-specific   •Illegal feature      Configured Components
 concepts           combinations
•Features          •Default settings &
                    dependencies
                   •Construction rules
                   •Optimisations
                                         Generic Components

                                                        ACCU 2006
                                                   © Schalk W. Cronjé
Steps
●   Domain scoping
●   Feature & concept modelling
●   Common architecture design, implementation and
    technology identification
●   Domain-specific notations (DSLs)
●   Specify configuration knowledge (metadata)
●   Implement generic components
●   Apply configuration knowledge using generators

    There is no specific order to these steps !


                                                       ACCU 2006
                                                  © Schalk W. Cronjé
Configuration Knowledge vs
Metadata
●   Configuration knowledge is the term preferred by
    Czarnecki & Eisenecker
●   Configuration knowledge can be considered the
    holistic encapsulation of all knowledge related to
    building all variants
●   Metadata is probably a more codified form of
    configuration knowledge.
●   Some people find the term metadata easier to grasp
    and less confusing than configuration knowledge
●   The rest of this presentation uses the term metadata
●   DSL is a notation for capturing metadata


                                                     ACCU 2006
                                                © Schalk W. Cronjé
Key Code-level Strategy




                               ACCU 2006
                          © Schalk W. Cronjé
For effective implementation there is one basic principle
that encompasses most GP strategies:

           Dijkstra's Separation of Concerns

This principle accepts the fact that we cannot deal with
many issues at once and that important issues should
be addressed with purpose.




                                                    ACCU 2006
                                               © Schalk W. Cronjé
Key Code-level Strategies
●   Develop elementary components as generic
    components
     – Fully testable outside of the intended product
       configuration
●   Configure these components using generated
    artefacts appropriate to the programming language
●   Aim for zero cyclomatic-complexity in the generated
    artefacts
●   Eliminate defects as early as possible



                                                    ACCU 2006
                                               © Schalk W. Cronjé
McCall's Quality Factors Addressed

●   Correctness       ●   Testability
●   Reliability       ●   Flexibility
●   Usability         ●   Integrity
●   Maintainability   ●   Reusability
●   Portability       ●   Interoperability
●   Efficiency




                                             ACCU 2006
                                        © Schalk W. Cronjé
Techniques for C++




                          ACCU 2006
                     © Schalk W. Cronjé
Strategies for C++
●   Templates are the C++ way to generic programming
●   Develop elementary components as generic
    components
     – Fully testable outside of the intended product
       configuration
●   Configure these components using generated traits /
    policy classes
●   Aim for zero cyclomatic-complexity in the generated
    classes



                                                    ACCU 2006
                                               © Schalk W. Cronjé
Template Metaprogramming
●   MPL is a key technology to build generic components
    –   Best example is Boost C++ MPL
●   MPL has been suggested as a domain-specific
    language
    –   Metadata difficult to review to someone not familiar with
        MPL
●   MPL should rather be used as implementation
    strategy




                                                               ACCU 2006
                                                          © Schalk W. Cronjé
Example #1: Configuration system
Name: NetworkPort
Description: Unrestricted port on which a service
  can be started
Type: uint16
Minimum Value: 1024
Maximum Value: 65535




                                                ACCU 2006
                                           © Schalk W. Cronjé
Example #1: Configuration system
template <typename CfgAttr>
typename CfgAttr::value_type
get_config();


std::cout << "The network port we'll use is " <<
  get_config<NetworkPort>();




                                                ACCU 2006
                                           © Schalk W. Cronjé
Example #1: A traits class
struct NetworkPort
{
  typedef uint16_t value_type;
  static const value_type const_min = 1024;
  static const value_type const_max = 65535;

  // ... rest to follow
};




                                                ACCU 2006
                                           © Schalk W. Cronjé
Example #1: Alternative traits

Because non-integral types cannot be initialised inline, it
might be more practical to use the following alternative.
struct NetworkPort
{
  typedef uint16_t value_type;
  static value_type min_value() {return 1024;}
  static value_type max_value() {return 65535;}

  // ... rest to follow
};




                                                      ACCU 2006
                                                 © Schalk W. Cronjé
Example #1: Basic generic function
std::string get_cfg_string( const char* name );

template <typename CfgAttr>
typename CfgAttr::value_type
get_config()
{
  // Calls a basic configuration interface function
  std::string tmp=get_cfg_string( CfgAttr::name() );

    // Converts to appropriate type, throws exception
    // on conversion failure
    return boost::lexical_cast<typename
      CfgAttr::value_type>(tmp);
}


                                                       ACCU 2006
                                                  © Schalk W. Cronjé
Introducing run-time safety
●   In order to protect the system against external invalid
    data we need to add boundary checks.
    –   Use min_value(), max_value() from traits
    –   Add a default_value() to handle missing data
●   Additional features could include:
    –   Throwing an exception, instead of defaulting, when data is
        missing.




                                                             ACCU 2006
                                                        © Schalk W. Cronjé
Example #1: Extending the function
template <typename CfgAttr>
typename CfgAttr::value_type
get_config()
{
  try
  {
    std::string tmp=get_cfg_string( CfgAttr::name() );
    typedef typename CfgAttr::value_type vtype;
    vtype ret= boost::lexical_cast<vtype>(tmp);
    return CfgAttr::bounded(ret);
  }
  catch(boost::bad_lexical_cast const&)
  {
    return CfgAttr::default_value();
  }
}

                                                    ACCU 2006
                                               © Schalk W. Cronjé
Example #1: Updated traits
struct NetworkPort
{
  typedef uint16_t value_type;
  static value_type min_value() {return 1024;}
  static value_type max_value() {return 65535;}
  static value_type default_value {return 4321;}

  static value_type& bounded(value_type& v_)
  {
    return v_=std::max(min_value(),std::min
      (v_,max_value()));
  }
};


                                                ACCU 2006
                                           © Schalk W. Cronjé
Capturing Metadata
●   Various methods have been used for codifying
    metadata into a DSL
     –   Text files
     –   Graphical Tools
     –   CASE Tools
●   XML is a very convenient form for new projects
     –   Semi-human readable
     –   Text – Unrestricted source-control
     –   Easy to transform to other formats
          ●   Includes non-code artefacts
     –Custom editor can be created in Python or Java
●   XML can restrict flexibility of DSL.

                                                            ACCU 2006
                                                       © Schalk W. Cronjé
Example #1: Configuration system
<ConfigSystem>
  <Attr name="NetworkPort" adt="uint16">
    <Description>Unrestricted port on which a
  service can be started</Description>
    <Min>1024</Min>
    <Max>65535</Max>
    <Default>4321</Default>
  </Attr>
</ConfigSystem>




                                                ACCU 2006
                                           © Schalk W. Cronjé
Prefer ADTs
●   Use abstract data types (ADTs)
●   Use a XML lookup table to go from ADT to C++ type
●   Underlying C++ representation can be changed
    without changing any of the metadata




                                                  ACCU 2006
                                             © Schalk W. Cronjé
Example #1: Simple Generator
<xsl:template match="Attr">
struct <xsl:value-of select="@name"/>
{
   typedef <xsl:apply-templates select="." mode="adt"/>
   value_type;
   static const char* name() {return &quot;<xsl:value-of
   select="@name"/>&quot;;}
   static value_type min_value() {return <xsl:value-of
   select="Min/text()"/>;}
   static value_type max_value() {return <xsl:value-of
   select="Max/text()"/>;}
   static value_type default_value() {return <xsl:value-of
   select="Default/text()"/>;}
};
</xsl:template>


                                                     ACCU 2006
                                                © Schalk W. Cronjé
Example #1: Simple Generator
<xsl:template match="Attr">
  <xsl:text>struct </xsl:text>
                               (with xsl:text)
  <xsl:value-of select="@name"/>
  <xsl:text>&#10;{&#10;&#9; typedef </xsl:text>
  <xsl:apply-templates select="." mode="adt"/>
  <xsl:text> value_type;&#10;&#9;</xsl:text>
  <xsl:text>static const char* name() {return &quot;</xsl:text>
  <xsl:value-of select="@name"/>
  <xsl:text>&quot;;}&#10;&#9;<xsl:text>
  <xsl:text>static value_type min_value() {return </xsl:text>
  <xsl:value-of select="Min/text()"/>
  <xsl:text>;}&#10;&#9;</xsl:text>
  <xsl:text>static value_type max_value() {return </xsl:text>
  <xsl:value-of select="Max/text()"/>
  <xsl:text>;}&#10;&#9;</xsl:text>
  <xsl:text>static value_type default_value() {return </xsl:text>
  <xsl:value-of select="Default/text()"/>
  <xsl:text>;}&#10;};&#10;</xsl:text>
</xsl:template>
                                                          ACCU 2006
                                                     © Schalk W. Cronjé
ADT Lookup Table
<types>
  <type adt="uint16">
     <cpp type="uint16_t" quoted="no"/>
  </type>
  <type adt="string">
     <cpp type="std::string" quoted="yes"/>
  </type>
<!--
  adt: ADT name
  cpp/@type: What type to use on a C++ system
  cpp/@quoted: Whether to quote the type in a traits
  class
-->
</types>



                                                     ACCU 2006
                                                © Schalk W. Cronjé
Generating code documentation
/** Unrestricted port on which a service can
* be started.
*
* @ingroup Configuration
*/
struct NetworkPort
{
   // ... Generated traits
};




                                                ACCU 2006
                                           © Schalk W. Cronjé
Example #2
●   Logging and reporting are aspects of most systems
    that cut across the architecture.
●   There might be many requirements in your system,
    on how logging and reporting will be used.
    –   Loggable entities
    –   Levels of logging
    –   User display issues
    –   Localisation
●   From a C++ point-of-view one important feature is
    how logging is generated at logging points
●   Using a GP approach it is possible to introduce
    compile-time validation

                                                    ACCU 2006
                                               © Schalk W. Cronjé
Example #2: Legacy Logging
#define MINOR_FAILURE 10
#define MAJOR_PROBLEM 20
#define GENERAL_PANIC 30

void log_it( int id, const char* text );




// and then some cowboy programmer comes along
log_it(
   MINOR_PROBLEM|GENERAL_PANIC,
   ”Voila!! An unsupported error”
);




                                                      ACCU 2006
                                                 © Schalk W. Cronjé
Example #2: Logging Metadata
<Logging>
  <Report id=”10” name=”MINOR_FAILURE”>
   <Text>The projector's bulb needs replacing</Text>
  </Report>
  <Report id=”20” name=”MAJOR_PROBLEM”>
    <Text>We're out of Belgium beer</Text>
  </Report>
  <Report id=”30” name=”GENERAL_PANIC”>
    <Text>David Beckham spotted outside Randolph</Text>
  </Report>
</Logging>




                                                     ACCU 2006
                                                © Schalk W. Cronjé
Example #2: Logging Function
template <typename Report>
void log_it( Report const&, const char* text );

log_it( 3,”My code” ); // compile error

log_it( MAJOR_PROBLEM, “Out of German beer too” );

log_it(
  MINOR_FAILURE|MAJOR_PROBLEM,
  “No way” ); // Compile error




                                                       ACCU 2006
                                                  © Schalk W. Cronjé
Example #2: Logging ID Class
// Define type
class Reportable
{
   public:
     explicit Reportable( unsigned id_ );
     unsigned id() const;
};

// then do either, initialising MINOR_FAILURE in .cpp
extern const Reportable MINOR_FAILURE;

// or
namespace { const Reportable MINOR_FAILURE =
  Reportable(10); }



                                                     ACCU 2006
                                                © Schalk W. Cronjé
Preventing C++ Code-bloat
●   Only instantiate what is needed
     –  For constant objects this is very easy using the MPL-value
        idiom
●   Due to ways some linkers work, concrete code might be
    included in a final link even if the code is not used, therefore
    only generate what is needed
     – Control the config elements available to a specific system
        from metadata
     – Only generate the appropriate traits classes
●   Cleanly separate common concrete code into a mixin class




                                                               ACCU 2006
                                                          © Schalk W. Cronjé
The MPL-value idiom
template <unsigned V>
class A
{
  public:
    static const A<V> value;

  private:
    A();
};

template <unsigned V>
static const A<V> A<V>::value;



                                      ACCU 2006
                                 © Schalk W. Cronjé
Logging Reworked
template <unsigned id_>
class Reportable
{
   public:
     unsigned id() const {return id_;}
     static const Reportable<id_> value;
};
const Reportable<id_> Reportable<id_>::value;

typedef Reportable<10> MINOR_FAILURE;

log_it( MINOR_FAILURE::value,”Only instantiated when
  used”);




                                                     ACCU 2006
                                                © Schalk W. Cronjé
Adding logging actions
●   A user might want to specify that some reports can have
    certain associated actions.
●   For the logging example we might have
     – GO_BUY
     – MAKE_ANNOUNCEMENT
     – CALL_SECURITY.
●   As this is configuration knowledge we can add this to
    the metadata and then generate appropriate
    metacode.




                                                           ACCU 2006
                                                      © Schalk W. Cronjé
Example #2: Logging Metadata
<Logging>
  <Report id=”10” name=”MINOR_FAILURE”>
   <Action>GO_BUY</Action>
  </Report>
  <Report id=”20” name=”MAJOR_PROBLEM”>
    <Action>GO_BUY</Action>
    <Action>MAKE_ANNOUNCEMENT</Action>
  </Report>
  <Report id=”30” name=”GENERAL_PANIC”>
    <Action>CALL_SECURITY</Action>
    <Action>MAKE_ANNOUNCEMENT</Action>
  </Report>
</Logging>




                                               ACCU 2006
                                          © Schalk W. Cronjé
Using MPL as glue
template <unsigned id_,typename actions_list>
struct Reportable
{
    BOOST_STATIC_CONSTANT(unsigned,id=id_);

    typedef actions_list valid_actions;
};
// Generated code
typedef Reportable<20,
   boost::mpl::vector<GO_BUY,MAKE_ANNOUNCEMENT>
> MAJOR_PROBLEM;




                                                       ACCU 2006
                                                  © Schalk W. Cronjé
Using SFINAE as validator
template <typename Report,typename Action>
void log_it( const char* text,
  typename boost::enable_if<
   boost::mpl::contains<
     typename Report::valid_actions, Action
   >
  >::type*_= 0);

// Fails to compile – no suitable function
log_it<GENERAL_PANIC,GO_BUY>("Bought Posh a drink");

// OK,
log_it<MAJOR_PROBLEM,GO_BUY>("Imported some Hoegaarden");



                                                     ACCU 2006
                                                © Schalk W. Cronjé
Using static assertion as validator
template <typename Report,typename Action>
void log_it( const char* text )
{
  BOOST_MPL_ASSERT((
     boost::mpl::contains<
      typename Report::valid_actions, Action
   > ));

    // implementation follows after MPL assert ...
}




                                                          ACCU 2006
                                                     © Schalk W. Cronjé
Techniques for C




                        ACCU 2006
                   © Schalk W. Cronjé
Strategies for C
●   C has nowhere near the power and flexibility of C++,
    but basic principles remain the same
     – Configure generic components using generated
       macros
     – Aim for zero cyclomatic-complexity in the macros
●   Use indirect naming in order to attempt a bit of
    compile-time safety
     – Hide void* and varargs from programmer
●   Use types as a strategy for compile-time validation
     – C does not place parameter types in symbols
     – Type manipulation will not create excessive
       symbol tables

                                                     ACCU 2006
                                                © Schalk W. Cronjé
Example #3: C Configuration system
/* Public interface via macros */
#define CONFIG_TYPE( CFGATTR ) .....
#define CONFIG_TOKEN( CFGATTR,EXTRA ) ....
#define CONFIG_GET( CFGATTR,VAR ) ....

CONFIG_TYPE(NetworkPort) v;
printf( "The network port we'll use is "
  CONFIG_TOKEN(NetworkPort,"") "n",
  * CONFIG_GET(NetworkPort,v)
);




                                                  ACCU 2006
                                             © Schalk W. Cronjé
Example #3: Implementation
void* config_get__(
    char const* pName_,
    size_t varsize_,
    void * var_,
    ...
);


                          Pass in order:
                          •Function for setting default
                          •Pointer to default value
                          •Function for setting bounds
                          •Pointer to minimum value
                          •Pointer to maximum value




                                                          ACCU 2006
                                                     © Schalk W. Cronjé
Example #3: Generic Macros
#define CONFIG_TYPE( CFGATTR ) 
   AUTOGENCFG_TYPE_##CFGATTR

#define CONFIG_TOKEN( CFGATTR,EXTRA ) 
  "%" EXTRA AUTOGENCFG_TOKEN_##CFGATTR

#define CONFIG_GET( CFGATTR,VAR ) 
  ( CONFIG_TYPE(CFGATTR) *) config_get__( 
  AUTOGENCFG_NAME_##CFGATTR, 
  sizeof( CONFIG_TYPE(CFGATTR) ), 
  & VAR,                               Hide implementation
  AUTOGENCFG_DEFAULTF_##CFGATTR,       inside macro
  AUTOGENCFG_DEFAULT_##CFGATTR, 
  AUTOGENCFG_BOUNDF_##CFGATTR, 
  AUTOGENCFG_MIN_##CFGATTR, 
  AUTOGENCFG_MAX_##CFGATTR )
                                                      ACCU 2006
                                                 © Schalk W. Cronjé
Example #3: Generated Macros
#define AUTOGENCFG_TYPE_NetworkPort     uint16_t
#define AUTOGENCFG_TOKEN_NetworkPort    "hu"
#define AUTOGENCFG_NAME_NetworkPort     
     "sys.network.port"
#define AUTOGENCFG_DEFAULTF_NetworkPort 
     &config_set_default__
#define AUTOGENCFG_DEFAULT_NetworkPort    1234
#define AUTOGENCFG_BOUNDF_NetworkPort     
     &config_bound_ushort__
#define AUTOGENCFG_MIN_NetworkPort        1024
#define AUTOGENCFG_MAX_NetworkPort        65535




                                                 ACCU 2006
                                            © Schalk W. Cronjé
Updated ADT Lookup Table
<types>
  <type adt="uint16">
     <cpp type="uint16_t" quoted="no"/>
     <c type="uint16_t" quoted="no"/>
  </type>
  <type adt="string">
     <cpp type="std::string" quoted="yes"/>
     <c type="const char*" quoted="yes"/>
  </type>
<!--
  c/@type: What type to use on a C system
  c/@quoted: Whether to quote the type in a macro
  definition
-->
</types>


                                                     ACCU 2006
                                                © Schalk W. Cronjé
Example #4: C Logging System
/* Public interface via macro */

#define LOG_IT( LOGNAME,ACTION,TEXT ) ....

// Valid rule
LOG_IT( MAJOR_PROBLEM,GO_BUY,
                "Bought some Hoegaarden" );

// Invalid combination – fails to compile
LOG_IT( MAJOR_PROBLEM,CALL_SECURITY,
                "Bought some Hoegaarden" );




                                                   ACCU 2006
                                              © Schalk W. Cronjé
Example #4: Generated C
/* Events and as macros */
#define AUTOGENLOG_ID_MINOR_FAILURE 10
#define AUTOGENLOG_ID_MAJOR_PROBLEM 20
#define AUTOGENLOG_ID_GENERAL_PANIC 30

#define AUTOGENLOG_ACTION_GO_BUY 1
#define AUTOGENLOG_ACTION_CALL_SECURITY 2
#define AUTOGENLOG_ACTION_MAKE_ANNOUNCEMENT 3

/* Valid combinations as union */
union AUTOGENLOG_ACTIONS_MAJOR_PROBLEM { unsigned long
   GO_BUY; unsigned long MAKE_ANNOUNCEMENT; };



                                                 ACCU 2006
                                            © Schalk W. Cronjé
Example #4: C Implementation
/* Implementation function
    Internals left as exercise for the reader
*/
void log_it__(
   unsigned long id,                 Use union member to
   unsigned long action,             perform compile-time validation
   const char* text );

#define LOG_IT( LOGNAME,ACTION,TEXT ) do { 
  auto union AUTOGENLOG_ACTIONS_##LOGNAME x; 
  x. ACTION = AUTOGENLOG_ACTION_##ACTION; 
  log_it__( AUTOGENLOG_ID_##LOGNAME,x. ACTION,TEXT); 
} while(0)


                                                            ACCU 2006
                                                       © Schalk W. Cronjé
Preventing C Code-bloat
●   Keep generated code in macros and type definitions
    where possible.
●   Keep executable code inside macros simplistic and to
    a minimum
●   Rely on compiler optimisation for where duplication
    cannot be avoided
●   Cleanly separate common code into testable
    functions




                                                    ACCU 2006
                                               © Schalk W. Cronjé
Techniques for
Scripting / Dynamic Languages




                              ACCU 2006
                         © Schalk W. Cronjé
Dispelling Myths about Reflection

●   Myth #1: I don't need GP because language
    X has reflection
●   Myth #2: I don't need reflection because I am
    using GP
●   Fact: GP maps the domain knowledge,
    captured in a non-programming language, into
    a programming language.
    –   If reflection is the most effective way of doing this
        in language X, then it should be used.


                                                         ACCU 2006
                                                    © Schalk W. Cronjé
Problems with Build-time Validation

●   Early validation at build-time is not always
    trivial
●   Perl can sometimes use -c switch
●   JavaScript is difficult
●   Sometimes validation has to be pushed out to
    unit tests
    –   Should never require system testing to provide
        the validation




                                                     ACCU 2006
                                                © Schalk W. Cronjé
Example #5: JavaScript Configuration
// For writing and reading configuration files

function get_config( CFGNAME );
function get_config_text( CFGNAME );
function set_config( CFGNAME, new_value );

document.write(
   get_config_text(NetworkPort),
   ": ", get_config(NetworkPort)
);

                                   Will display text description
                                   from metadata (suitably localised)



                                                           ACCU 2006
                                                      © Schalk W. Cronjé
Example #5: Generated JS Traits
// Autogenerated 'traits'
var NetworkPort = new Object;
NetworkPort.min = 1024;
NetworkPort.max = 65535;
NetworkPort.defaultvalue= 1234;
NetworkPort.path= "subsystem.network.port";

// Validate functions are first-class variables
NetworkPort.validate= validate_integral;

// Localised text setting
NetworkPort.descr.en = "Unrestricted port on which a
  service can be started";


                                                   ACCU 2006
                                              © Schalk W. Cronjé
Example #5: JS Config Read
// Reads a variable from a path in a config file
// Implementation is system-dependant
function get_from_config_file( Path ) { /* ... */ }

function get_config( CFGNAME )
{
     var tmp = get_from_config_file( CFGNAME.path );
     if( tmp == null )
        return CFGNAME.defaultvalue;
     else
        return tmp;
}



                                                ACCU 2006
                                           © Schalk W. Cronjé
Example #5: JS Config Write
// Writes a new value to the path in a config file
// Implementation is system-dependant

function set_in_config_file( Path,Value )
{/* .... */}

function set_config( CFGNAME, new_value )
{
  if(typeof (new_value) != typeof
  (CFGNAME.defaultvalue) )
       throw "Invalid Type Applied";
  CFGNAME.validate(new_value,CFGNAME.min,CFGNAME.max);
  set_in_config_file( CFGNAME.path, new_value);
}

                                                 ACCU 2006
                                            © Schalk W. Cronjé
Updated ADT Lookup Table
<types>
  <type adt="uint16">
     ...
     <js type="Number"   quoted="no"/>
  </type>
  <type adt=”string”>
     ...
     <js type="String"   quoted="yes"/>
  </type>
<!--
  js/@type: What type    to use in JavaScript
  js/@quoted: Whether    to quote the type initialisation
-->
</types>



                                                        ACCU 2006
                                                   © Schalk W. Cronjé
Updated ADT Lookup Table
<types>               (no types)
  <type adt="uint16">
     ...
     <js quoted="no"/>
  </type>
  <type adt="string">
     ...
     <js quoted="yes"/>
  </type>
<!--
  js/@quoted: Whether to quote the type initialisation
-->
</types>




                                                     ACCU 2006
                                                © Schalk W. Cronjé
The Bigger Picture




                          ACCU 2006
                     © Schalk W. Cronjé
Multiple Systems
●   Examples until now have shown the GP steps for a
    configuration system and a logging system.
●   The next step is to apply these to three systems:
    –   System 1 uses XML files for configuration and sends logs
        to syslog.
    –   System2 uses INI files, and sends logs to NT Evlog
    –   System 3 keeps configuration in a binary format (read-only)
        and sends logs via SNMP.




                                                             ACCU 2006
                                                        © Schalk W. Cronjé
Example Product Metadata
<Products>
  <System id=”1”>
    <Config type=”xml”/>
    <Logging type=”syslog”/>
    <Functionality> ... <Functionality>
  </System>
  <System id=”2”>
    <Config type=”ini”/>
    <Logging type=”ntevlog”/>
    <Functionality> ... <Functionality>
  </System>
</Products>




                                               ACCU 2006
                                          © Schalk W. Cronjé
Building Multiple Systems
●   Four generators can be applied to this product
    metadata.
    –   Two of them we have already seen
    –   These will generate configurations and logging aspects
●   Another generator looks at logging and configurations
    and adds the appropriate subsystems.
●   A fourth generator looks at the functionality and loads
    up all of the functional classes for the system
    –   A creative exercise for the reader …




                                                            ACCU 2006
                                                       © Schalk W. Cronjé
Integration
●   Many modern systems are multi-language / multi-
    platform
●   These techniques extend easily into other
    programming languages / development environments
●   The same configuration knowledge remains the
    driver
●   Localisation data can be generated in various formats
●   Parts of technical documents can also be generated.




                                                    ACCU 2006
                                               © Schalk W. Cronjé
Bad smells
●   The unit tests are generated
    –   How can you verify that the generated tests is correct?
    –   Generating test inputs & outputs are acceptable
●   There is business logic in the generators
    –   The DSL is probably incorrect
●   The generated code is edited before usage
    –   Artefacts are not templates
●   Every build takes very long
    –   Dependency checking must be improved




                                                              ACCU 2006
                                                         © Schalk W. Cronjé
Further Reading

●   www.program-transformation.org
●   www.generative-programming.org
●   www.codegeneration.net
●   research.microsoft.com
●   www.martinfowler.com




                                          ACCU 2006
                                     © Schalk W. Cronjé

Más contenido relacionado

La actualidad más candente

CUDA by Example : Graphics Interoperability : Notes
CUDA by Example : Graphics Interoperability : NotesCUDA by Example : Graphics Interoperability : Notes
CUDA by Example : Graphics Interoperability : Notes
Subhajit Sahu
 

La actualidad más candente (20)

Matrix Multiplication with Ateji PX for Java
Matrix Multiplication with Ateji PX for JavaMatrix Multiplication with Ateji PX for Java
Matrix Multiplication with Ateji PX for Java
 
System verilog assertions
System verilog assertionsSystem verilog assertions
System verilog assertions
 
CUDA by Example : Graphics Interoperability : Notes
CUDA by Example : Graphics Interoperability : NotesCUDA by Example : Graphics Interoperability : Notes
CUDA by Example : Graphics Interoperability : Notes
 
Verilog HDL - 3
Verilog HDL - 3Verilog HDL - 3
Verilog HDL - 3
 
OpenGL Based Testing Tool Architecture for Exascale Computing
OpenGL Based Testing Tool Architecture for Exascale ComputingOpenGL Based Testing Tool Architecture for Exascale Computing
OpenGL Based Testing Tool Architecture for Exascale Computing
 
Go Faster With Native Compilation
Go Faster With Native CompilationGo Faster With Native Compilation
Go Faster With Native Compilation
 
Qt for Python
Qt for PythonQt for Python
Qt for Python
 
PT-4057, Automated CUDA-to-OpenCL™ Translation with CU2CL: What's Next?, by W...
PT-4057, Automated CUDA-to-OpenCL™ Translation with CU2CL: What's Next?, by W...PT-4057, Automated CUDA-to-OpenCL™ Translation with CU2CL: What's Next?, by W...
PT-4057, Automated CUDA-to-OpenCL™ Translation with CU2CL: What's Next?, by W...
 
CC-4000, Characterizing APU Performance in HadoopCL on Heterogeneous Distribu...
CC-4000, Characterizing APU Performance in HadoopCL on Heterogeneous Distribu...CC-4000, Characterizing APU Performance in HadoopCL on Heterogeneous Distribu...
CC-4000, Characterizing APU Performance in HadoopCL on Heterogeneous Distribu...
 
Hybrid Model Based Testing Tool Architecture for Exascale Computing System
Hybrid Model Based Testing Tool Architecture for Exascale Computing SystemHybrid Model Based Testing Tool Architecture for Exascale Computing System
Hybrid Model Based Testing Tool Architecture for Exascale Computing System
 
Syntutic
SyntuticSyntutic
Syntutic
 
An Introductory course on Verilog HDL-Verilog hdl ppr
An Introductory course on Verilog HDL-Verilog hdl pprAn Introductory course on Verilog HDL-Verilog hdl ppr
An Introductory course on Verilog HDL-Verilog hdl ppr
 
A Domain-Specific Embedded Language for Programming Parallel Architectures.
A Domain-Specific Embedded Language for Programming Parallel Architectures.A Domain-Specific Embedded Language for Programming Parallel Architectures.
A Domain-Specific Embedded Language for Programming Parallel Architectures.
 
GCC RTL and Machine Description
GCC RTL and Machine DescriptionGCC RTL and Machine Description
GCC RTL and Machine Description
 
GS-4108, Direct Compute in Gaming, by Bill Bilodeau
GS-4108, Direct Compute in Gaming, by Bill BilodeauGS-4108, Direct Compute in Gaming, by Bill Bilodeau
GS-4108, Direct Compute in Gaming, by Bill Bilodeau
 
PT-4102, Simulation, Compilation and Debugging of OpenCL on the AMD Southern ...
PT-4102, Simulation, Compilation and Debugging of OpenCL on the AMD Southern ...PT-4102, Simulation, Compilation and Debugging of OpenCL on the AMD Southern ...
PT-4102, Simulation, Compilation and Debugging of OpenCL on the AMD Southern ...
 
Migrating from OpenGL to Vulkan
Migrating from OpenGL to VulkanMigrating from OpenGL to Vulkan
Migrating from OpenGL to Vulkan
 
PG-4034, Using OpenGL and DirectX for Heterogeneous Compute, by Karl Hillesland
PG-4034, Using OpenGL and DirectX for Heterogeneous Compute, by Karl HilleslandPG-4034, Using OpenGL and DirectX for Heterogeneous Compute, by Karl Hillesland
PG-4034, Using OpenGL and DirectX for Heterogeneous Compute, by Karl Hillesland
 
CC-4010, Bringing Spatial Love to your Java Application, by Steven Citron-Pousty
CC-4010, Bringing Spatial Love to your Java Application, by Steven Citron-PoustyCC-4010, Bringing Spatial Love to your Java Application, by Steven Citron-Pousty
CC-4010, Bringing Spatial Love to your Java Application, by Steven Citron-Pousty
 
OpenGL 4.5 Update for NVIDIA GPUs
OpenGL 4.5 Update for NVIDIA GPUsOpenGL 4.5 Update for NVIDIA GPUs
OpenGL 4.5 Update for NVIDIA GPUs
 

Destacado

Practical Meta Programming
Practical Meta ProgrammingPractical Meta Programming
Practical Meta Programming
Reggie Meisler
 
Generative programming (mostly parser generation)
Generative programming (mostly parser generation)Generative programming (mostly parser generation)
Generative programming (mostly parser generation)
Ralf Laemmel
 
Transformational-Generative Grammar
Transformational-Generative GrammarTransformational-Generative Grammar
Transformational-Generative Grammar
Ruth Ann Llego
 
Ubiquitous Computing
Ubiquitous ComputingUbiquitous Computing
Ubiquitous Computing
u065932
 

Destacado (12)

Seeking Enligtenment - A journey of purpose rather tan instruction
Seeking Enligtenment - A journey of purpose rather tan instructionSeeking Enligtenment - A journey of purpose rather tan instruction
Seeking Enligtenment - A journey of purpose rather tan instruction
 
Practical Meta Programming
Practical Meta ProgrammingPractical Meta Programming
Practical Meta Programming
 
A Generative Programming Approach to Developing Pervasive Computing Systems
A Generative Programming Approach to Developing Pervasive Computing SystemsA Generative Programming Approach to Developing Pervasive Computing Systems
A Generative Programming Approach to Developing Pervasive Computing Systems
 
Generative programming (mostly parser generation)
Generative programming (mostly parser generation)Generative programming (mostly parser generation)
Generative programming (mostly parser generation)
 
Generative and Meta-Programming - Modern C++ Design for Parallel Computing
Generative and Meta-Programming - Modern C++ Design for Parallel ComputingGenerative and Meta-Programming - Modern C++ Design for Parallel Computing
Generative and Meta-Programming - Modern C++ Design for Parallel Computing
 
Japanese Open and Generative Design
Japanese Open and Generative DesignJapanese Open and Generative Design
Japanese Open and Generative Design
 
Seri Belajar Mandiri - Pemrograman C# Untuk Pemula
Seri Belajar Mandiri - Pemrograman C# Untuk PemulaSeri Belajar Mandiri - Pemrograman C# Untuk Pemula
Seri Belajar Mandiri - Pemrograman C# Untuk Pemula
 
Probabilistic programming
Probabilistic programmingProbabilistic programming
Probabilistic programming
 
Summary - Transformational-Generative Theory
Summary - Transformational-Generative TheorySummary - Transformational-Generative Theory
Summary - Transformational-Generative Theory
 
Transformational-Generative Grammar
Transformational-Generative GrammarTransformational-Generative Grammar
Transformational-Generative Grammar
 
Deep structure and surface structure
Deep structure and surface structureDeep structure and surface structure
Deep structure and surface structure
 
Ubiquitous Computing
Ubiquitous ComputingUbiquitous Computing
Ubiquitous Computing
 

Similar a Practical Multi-language Generative Programming

VLSI Training presentation
VLSI Training presentationVLSI Training presentation
VLSI Training presentation
Daola Khungur
 

Similar a Practical Multi-language Generative Programming (20)

Asynchronous Functions In C++
Asynchronous Functions In C++Asynchronous Functions In C++
Asynchronous Functions In C++
 
GNAT Pro User Day: QGen: Simulink® static verification and code generation
GNAT Pro User Day: QGen: Simulink® static verification and code generationGNAT Pro User Day: QGen: Simulink® static verification and code generation
GNAT Pro User Day: QGen: Simulink® static verification and code generation
 
From Monolith to Modules - breaking apart a one size fits all product into mo...
From Monolith to Modules - breaking apart a one size fits all product into mo...From Monolith to Modules - breaking apart a one size fits all product into mo...
From Monolith to Modules - breaking apart a one size fits all product into mo...
 
QGen GNAT Industrial User Day
QGen GNAT Industrial User DayQGen GNAT Industrial User Day
QGen GNAT Industrial User Day
 
Gradle
GradleGradle
Gradle
 
SRE & Kubernetes
SRE & KubernetesSRE & Kubernetes
SRE & Kubernetes
 
Software Development Best Practices: Separating UI from Business Logic
Software Development Best Practices: Separating UI from Business LogicSoftware Development Best Practices: Separating UI from Business Logic
Software Development Best Practices: Separating UI from Business Logic
 
Rapid app building with loopback framework
Rapid app building with loopback frameworkRapid app building with loopback framework
Rapid app building with loopback framework
 
OCCIware Year 1 Milestone: Docker Studio, Studio Factory, pluggable XaaS runt...
OCCIware Year 1 Milestone: Docker Studio, Studio Factory, pluggable XaaS runt...OCCIware Year 1 Milestone: Docker Studio, Studio Factory, pluggable XaaS runt...
OCCIware Year 1 Milestone: Docker Studio, Studio Factory, pluggable XaaS runt...
 
OCCIware Cloud Expo London 2016 - Docker Studio, Studio Factory, erocci bus &...
OCCIware Cloud Expo London 2016 - Docker Studio, Studio Factory, erocci bus &...OCCIware Cloud Expo London 2016 - Docker Studio, Studio Factory, erocci bus &...
OCCIware Cloud Expo London 2016 - Docker Studio, Studio Factory, erocci bus &...
 
Boosting your HTML Apps – Overview of OpenCL and Hello World of WebCL
Boosting your HTML Apps – Overview of OpenCL and Hello World of WebCLBoosting your HTML Apps – Overview of OpenCL and Hello World of WebCL
Boosting your HTML Apps – Overview of OpenCL and Hello World of WebCL
 
VLSI Training presentation
VLSI Training presentationVLSI Training presentation
VLSI Training presentation
 
Groovy-Powered Microservices with Micronaut
Groovy-Powered Microservices with MicronautGroovy-Powered Microservices with Micronaut
Groovy-Powered Microservices with Micronaut
 
CNCF On-Demand Webinar_ LitmusChaos Project Updates.pdf
CNCF On-Demand Webinar_ LitmusChaos Project Updates.pdfCNCF On-Demand Webinar_ LitmusChaos Project Updates.pdf
CNCF On-Demand Webinar_ LitmusChaos Project Updates.pdf
 
"How to create an infrastructure in .NET", Leonid Chetverikov
"How to create an infrastructure in .NET", Leonid Chetverikov"How to create an infrastructure in .NET", Leonid Chetverikov
"How to create an infrastructure in .NET", Leonid Chetverikov
 
OCCIware @ Cloud Computing World 2016 - year 1 milestone & Linked Data demo
OCCIware @ Cloud Computing World 2016 - year 1 milestone & Linked Data demoOCCIware @ Cloud Computing World 2016 - year 1 milestone & Linked Data demo
OCCIware @ Cloud Computing World 2016 - year 1 milestone & Linked Data demo
 
Delivery Pipelines as a First Class Citizen @deliverAgile2019
Delivery Pipelines as a First Class Citizen @deliverAgile2019Delivery Pipelines as a First Class Citizen @deliverAgile2019
Delivery Pipelines as a First Class Citizen @deliverAgile2019
 
Thread and method_2010
Thread and method_2010Thread and method_2010
Thread and method_2010
 
GDG Cloud Southlake #8 Steve Cravens: Infrastructure as-Code (IaC) in 2022: ...
GDG Cloud Southlake #8  Steve Cravens: Infrastructure as-Code (IaC) in 2022: ...GDG Cloud Southlake #8  Steve Cravens: Infrastructure as-Code (IaC) in 2022: ...
GDG Cloud Southlake #8 Steve Cravens: Infrastructure as-Code (IaC) in 2022: ...
 
Component Based Model Driven Development of Mission Critical Defense Applicat...
Component Based Model Driven Development of Mission Critical Defense Applicat...Component Based Model Driven Development of Mission Critical Defense Applicat...
Component Based Model Driven Development of Mission Critical Defense Applicat...
 

Más de Schalk Cronjé

Más de Schalk Cronjé (20)

DocuOps & Asciidoctor in a JVM World
DocuOps & Asciidoctor in a JVM WorldDocuOps & Asciidoctor in a JVM World
DocuOps & Asciidoctor in a JVM World
 
DocuOps & Asciidoctor
DocuOps & AsciidoctorDocuOps & Asciidoctor
DocuOps & Asciidoctor
 
What's new in Asciidoctor
What's new in AsciidoctorWhat's new in Asciidoctor
What's new in Asciidoctor
 
Probability Management
Probability ManagementProbability Management
Probability Management
 
Seeking Enligtenment - A journey of purpose rather than instruction
Seeking Enligtenment  - A journey of purpose rather than instructionSeeking Enligtenment  - A journey of purpose rather than instruction
Seeking Enligtenment - A journey of purpose rather than instruction
 
Idiomatic Gradle Plugin Writing - GradleSummit 2016
Idiomatic Gradle Plugin Writing - GradleSummit 2016Idiomatic Gradle Plugin Writing - GradleSummit 2016
Idiomatic Gradle Plugin Writing - GradleSummit 2016
 
Gradle in 45min - JBCN2-16 version
Gradle in 45min - JBCN2-16 versionGradle in 45min - JBCN2-16 version
Gradle in 45min - JBCN2-16 version
 
Cool Jvm Tools to Help you Test - Aylesbury Testers Version
Cool Jvm Tools to Help you Test - Aylesbury Testers VersionCool Jvm Tools to Help you Test - Aylesbury Testers Version
Cool Jvm Tools to Help you Test - Aylesbury Testers Version
 
Cool JVM Tools to Help You Test
Cool JVM Tools to Help You TestCool JVM Tools to Help You Test
Cool JVM Tools to Help You Test
 
Using the Groovy Ecosystem for Rapid JVM Development
Using the Groovy Ecosystem for Rapid JVM DevelopmentUsing the Groovy Ecosystem for Rapid JVM Development
Using the Groovy Ecosystem for Rapid JVM Development
 
Gradle in 45min
Gradle in 45minGradle in 45min
Gradle in 45min
 
Basic Gradle Plugin Writing
Basic Gradle Plugin WritingBasic Gradle Plugin Writing
Basic Gradle Plugin Writing
 
Idiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin WritingIdiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin Writing
 
Beyond Estimates - Probability Management
Beyond Estimates - Probability ManagementBeyond Estimates - Probability Management
Beyond Estimates - Probability Management
 
Documentation An Engineering Problem Unsolved
Documentation  An Engineering Problem UnsolvedDocumentation  An Engineering Problem Unsolved
Documentation An Engineering Problem Unsolved
 
Idiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin WritingIdiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin Writing
 
Gradle in a Polyglot World
Gradle in a Polyglot WorldGradle in a Polyglot World
Gradle in a Polyglot World
 
Idiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin WritingIdiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin Writing
 
Death of Agile : Welcome to Value-focused Testing
Death of Agile : Welcome to Value-focused TestingDeath of Agile : Welcome to Value-focused Testing
Death of Agile : Welcome to Value-focused Testing
 
Asciidoctor in 15min
Asciidoctor in 15minAsciidoctor in 15min
Asciidoctor in 15min
 

Practical Multi-language Generative Programming

  • 1. Practical Generative Programming Schalk W. Cronjé ACCU 2006 © Schalk W. Cronjé
  • 2. Even in this new millennium, many engineers will still build components that have very little reuse potential due to the inflexible way that they were constructed. This leads to excessive time required to adapt a component for usage in another system. ACCU 2006 © Schalk W. Cronjé
  • 3. Welcome to the world of Generative Programming ACCU 2006 © Schalk W. Cronjé
  • 4. Themes ● GP 101 ● Building a single system ● C++ footwork ● Working with C ● Working with dynamic languages ● Building multiple systems ● Integration & testing ACCU 2006 © Schalk W. Cronjé
  • 5. Definition It is a software engineering paradigm where the aim is to automatically manufacture highly customised and optimised intermediate or end-products from elementary, reusable components by means of configuration knowledge. ACCU 2006 © Schalk W. Cronjé
  • 6. Elements of Generative Programming Configuration Knowledge Problem space Solution space •Domain-specific •Illegal feature Configured Components concepts combinations •Features •Default settings & dependencies •Construction rules •Optimisations Generic Components ACCU 2006 © Schalk W. Cronjé
  • 7. Steps ● Domain scoping ● Feature & concept modelling ● Common architecture design, implementation and technology identification ● Domain-specific notations (DSLs) ● Specify configuration knowledge (metadata) ● Implement generic components ● Apply configuration knowledge using generators There is no specific order to these steps ! ACCU 2006 © Schalk W. Cronjé
  • 8. Configuration Knowledge vs Metadata ● Configuration knowledge is the term preferred by Czarnecki & Eisenecker ● Configuration knowledge can be considered the holistic encapsulation of all knowledge related to building all variants ● Metadata is probably a more codified form of configuration knowledge. ● Some people find the term metadata easier to grasp and less confusing than configuration knowledge ● The rest of this presentation uses the term metadata ● DSL is a notation for capturing metadata ACCU 2006 © Schalk W. Cronjé
  • 9. Key Code-level Strategy ACCU 2006 © Schalk W. Cronjé
  • 10. For effective implementation there is one basic principle that encompasses most GP strategies: Dijkstra's Separation of Concerns This principle accepts the fact that we cannot deal with many issues at once and that important issues should be addressed with purpose. ACCU 2006 © Schalk W. Cronjé
  • 11. Key Code-level Strategies ● Develop elementary components as generic components – Fully testable outside of the intended product configuration ● Configure these components using generated artefacts appropriate to the programming language ● Aim for zero cyclomatic-complexity in the generated artefacts ● Eliminate defects as early as possible ACCU 2006 © Schalk W. Cronjé
  • 12. McCall's Quality Factors Addressed ● Correctness ● Testability ● Reliability ● Flexibility ● Usability ● Integrity ● Maintainability ● Reusability ● Portability ● Interoperability ● Efficiency ACCU 2006 © Schalk W. Cronjé
  • 13. Techniques for C++ ACCU 2006 © Schalk W. Cronjé
  • 14. Strategies for C++ ● Templates are the C++ way to generic programming ● Develop elementary components as generic components – Fully testable outside of the intended product configuration ● Configure these components using generated traits / policy classes ● Aim for zero cyclomatic-complexity in the generated classes ACCU 2006 © Schalk W. Cronjé
  • 15. Template Metaprogramming ● MPL is a key technology to build generic components – Best example is Boost C++ MPL ● MPL has been suggested as a domain-specific language – Metadata difficult to review to someone not familiar with MPL ● MPL should rather be used as implementation strategy ACCU 2006 © Schalk W. Cronjé
  • 16. Example #1: Configuration system Name: NetworkPort Description: Unrestricted port on which a service can be started Type: uint16 Minimum Value: 1024 Maximum Value: 65535 ACCU 2006 © Schalk W. Cronjé
  • 17. Example #1: Configuration system template <typename CfgAttr> typename CfgAttr::value_type get_config(); std::cout << "The network port we'll use is " << get_config<NetworkPort>(); ACCU 2006 © Schalk W. Cronjé
  • 18. Example #1: A traits class struct NetworkPort { typedef uint16_t value_type; static const value_type const_min = 1024; static const value_type const_max = 65535; // ... rest to follow }; ACCU 2006 © Schalk W. Cronjé
  • 19. Example #1: Alternative traits Because non-integral types cannot be initialised inline, it might be more practical to use the following alternative. struct NetworkPort { typedef uint16_t value_type; static value_type min_value() {return 1024;} static value_type max_value() {return 65535;} // ... rest to follow }; ACCU 2006 © Schalk W. Cronjé
  • 20. Example #1: Basic generic function std::string get_cfg_string( const char* name ); template <typename CfgAttr> typename CfgAttr::value_type get_config() { // Calls a basic configuration interface function std::string tmp=get_cfg_string( CfgAttr::name() ); // Converts to appropriate type, throws exception // on conversion failure return boost::lexical_cast<typename CfgAttr::value_type>(tmp); } ACCU 2006 © Schalk W. Cronjé
  • 21. Introducing run-time safety ● In order to protect the system against external invalid data we need to add boundary checks. – Use min_value(), max_value() from traits – Add a default_value() to handle missing data ● Additional features could include: – Throwing an exception, instead of defaulting, when data is missing. ACCU 2006 © Schalk W. Cronjé
  • 22. Example #1: Extending the function template <typename CfgAttr> typename CfgAttr::value_type get_config() { try { std::string tmp=get_cfg_string( CfgAttr::name() ); typedef typename CfgAttr::value_type vtype; vtype ret= boost::lexical_cast<vtype>(tmp); return CfgAttr::bounded(ret); } catch(boost::bad_lexical_cast const&) { return CfgAttr::default_value(); } } ACCU 2006 © Schalk W. Cronjé
  • 23. Example #1: Updated traits struct NetworkPort { typedef uint16_t value_type; static value_type min_value() {return 1024;} static value_type max_value() {return 65535;} static value_type default_value {return 4321;} static value_type& bounded(value_type& v_) { return v_=std::max(min_value(),std::min (v_,max_value())); } }; ACCU 2006 © Schalk W. Cronjé
  • 24. Capturing Metadata ● Various methods have been used for codifying metadata into a DSL – Text files – Graphical Tools – CASE Tools ● XML is a very convenient form for new projects – Semi-human readable – Text – Unrestricted source-control – Easy to transform to other formats ● Includes non-code artefacts –Custom editor can be created in Python or Java ● XML can restrict flexibility of DSL. ACCU 2006 © Schalk W. Cronjé
  • 25. Example #1: Configuration system <ConfigSystem> <Attr name="NetworkPort" adt="uint16"> <Description>Unrestricted port on which a service can be started</Description> <Min>1024</Min> <Max>65535</Max> <Default>4321</Default> </Attr> </ConfigSystem> ACCU 2006 © Schalk W. Cronjé
  • 26. Prefer ADTs ● Use abstract data types (ADTs) ● Use a XML lookup table to go from ADT to C++ type ● Underlying C++ representation can be changed without changing any of the metadata ACCU 2006 © Schalk W. Cronjé
  • 27. Example #1: Simple Generator <xsl:template match="Attr"> struct <xsl:value-of select="@name"/> { typedef <xsl:apply-templates select="." mode="adt"/> value_type; static const char* name() {return &quot;<xsl:value-of select="@name"/>&quot;;} static value_type min_value() {return <xsl:value-of select="Min/text()"/>;} static value_type max_value() {return <xsl:value-of select="Max/text()"/>;} static value_type default_value() {return <xsl:value-of select="Default/text()"/>;} }; </xsl:template> ACCU 2006 © Schalk W. Cronjé
  • 28. Example #1: Simple Generator <xsl:template match="Attr"> <xsl:text>struct </xsl:text> (with xsl:text) <xsl:value-of select="@name"/> <xsl:text>&#10;{&#10;&#9; typedef </xsl:text> <xsl:apply-templates select="." mode="adt"/> <xsl:text> value_type;&#10;&#9;</xsl:text> <xsl:text>static const char* name() {return &quot;</xsl:text> <xsl:value-of select="@name"/> <xsl:text>&quot;;}&#10;&#9;<xsl:text> <xsl:text>static value_type min_value() {return </xsl:text> <xsl:value-of select="Min/text()"/> <xsl:text>;}&#10;&#9;</xsl:text> <xsl:text>static value_type max_value() {return </xsl:text> <xsl:value-of select="Max/text()"/> <xsl:text>;}&#10;&#9;</xsl:text> <xsl:text>static value_type default_value() {return </xsl:text> <xsl:value-of select="Default/text()"/> <xsl:text>;}&#10;};&#10;</xsl:text> </xsl:template> ACCU 2006 © Schalk W. Cronjé
  • 29. ADT Lookup Table <types> <type adt="uint16"> <cpp type="uint16_t" quoted="no"/> </type> <type adt="string"> <cpp type="std::string" quoted="yes"/> </type> <!-- adt: ADT name cpp/@type: What type to use on a C++ system cpp/@quoted: Whether to quote the type in a traits class --> </types> ACCU 2006 © Schalk W. Cronjé
  • 30. Generating code documentation /** Unrestricted port on which a service can * be started. * * @ingroup Configuration */ struct NetworkPort { // ... Generated traits }; ACCU 2006 © Schalk W. Cronjé
  • 31. Example #2 ● Logging and reporting are aspects of most systems that cut across the architecture. ● There might be many requirements in your system, on how logging and reporting will be used. – Loggable entities – Levels of logging – User display issues – Localisation ● From a C++ point-of-view one important feature is how logging is generated at logging points ● Using a GP approach it is possible to introduce compile-time validation ACCU 2006 © Schalk W. Cronjé
  • 32. Example #2: Legacy Logging #define MINOR_FAILURE 10 #define MAJOR_PROBLEM 20 #define GENERAL_PANIC 30 void log_it( int id, const char* text ); // and then some cowboy programmer comes along log_it( MINOR_PROBLEM|GENERAL_PANIC, ”Voila!! An unsupported error” ); ACCU 2006 © Schalk W. Cronjé
  • 33. Example #2: Logging Metadata <Logging> <Report id=”10” name=”MINOR_FAILURE”> <Text>The projector's bulb needs replacing</Text> </Report> <Report id=”20” name=”MAJOR_PROBLEM”> <Text>We're out of Belgium beer</Text> </Report> <Report id=”30” name=”GENERAL_PANIC”> <Text>David Beckham spotted outside Randolph</Text> </Report> </Logging> ACCU 2006 © Schalk W. Cronjé
  • 34. Example #2: Logging Function template <typename Report> void log_it( Report const&, const char* text ); log_it( 3,”My code” ); // compile error log_it( MAJOR_PROBLEM, “Out of German beer too” ); log_it( MINOR_FAILURE|MAJOR_PROBLEM, “No way” ); // Compile error ACCU 2006 © Schalk W. Cronjé
  • 35. Example #2: Logging ID Class // Define type class Reportable { public: explicit Reportable( unsigned id_ ); unsigned id() const; }; // then do either, initialising MINOR_FAILURE in .cpp extern const Reportable MINOR_FAILURE; // or namespace { const Reportable MINOR_FAILURE = Reportable(10); } ACCU 2006 © Schalk W. Cronjé
  • 36. Preventing C++ Code-bloat ● Only instantiate what is needed – For constant objects this is very easy using the MPL-value idiom ● Due to ways some linkers work, concrete code might be included in a final link even if the code is not used, therefore only generate what is needed – Control the config elements available to a specific system from metadata – Only generate the appropriate traits classes ● Cleanly separate common concrete code into a mixin class ACCU 2006 © Schalk W. Cronjé
  • 37. The MPL-value idiom template <unsigned V> class A { public: static const A<V> value; private: A(); }; template <unsigned V> static const A<V> A<V>::value; ACCU 2006 © Schalk W. Cronjé
  • 38. Logging Reworked template <unsigned id_> class Reportable { public: unsigned id() const {return id_;} static const Reportable<id_> value; }; const Reportable<id_> Reportable<id_>::value; typedef Reportable<10> MINOR_FAILURE; log_it( MINOR_FAILURE::value,”Only instantiated when used”); ACCU 2006 © Schalk W. Cronjé
  • 39. Adding logging actions ● A user might want to specify that some reports can have certain associated actions. ● For the logging example we might have – GO_BUY – MAKE_ANNOUNCEMENT – CALL_SECURITY. ● As this is configuration knowledge we can add this to the metadata and then generate appropriate metacode. ACCU 2006 © Schalk W. Cronjé
  • 40. Example #2: Logging Metadata <Logging> <Report id=”10” name=”MINOR_FAILURE”> <Action>GO_BUY</Action> </Report> <Report id=”20” name=”MAJOR_PROBLEM”> <Action>GO_BUY</Action> <Action>MAKE_ANNOUNCEMENT</Action> </Report> <Report id=”30” name=”GENERAL_PANIC”> <Action>CALL_SECURITY</Action> <Action>MAKE_ANNOUNCEMENT</Action> </Report> </Logging> ACCU 2006 © Schalk W. Cronjé
  • 41. Using MPL as glue template <unsigned id_,typename actions_list> struct Reportable { BOOST_STATIC_CONSTANT(unsigned,id=id_); typedef actions_list valid_actions; }; // Generated code typedef Reportable<20, boost::mpl::vector<GO_BUY,MAKE_ANNOUNCEMENT> > MAJOR_PROBLEM; ACCU 2006 © Schalk W. Cronjé
  • 42. Using SFINAE as validator template <typename Report,typename Action> void log_it( const char* text, typename boost::enable_if< boost::mpl::contains< typename Report::valid_actions, Action > >::type*_= 0); // Fails to compile – no suitable function log_it<GENERAL_PANIC,GO_BUY>("Bought Posh a drink"); // OK, log_it<MAJOR_PROBLEM,GO_BUY>("Imported some Hoegaarden"); ACCU 2006 © Schalk W. Cronjé
  • 43. Using static assertion as validator template <typename Report,typename Action> void log_it( const char* text ) { BOOST_MPL_ASSERT(( boost::mpl::contains< typename Report::valid_actions, Action > )); // implementation follows after MPL assert ... } ACCU 2006 © Schalk W. Cronjé
  • 44. Techniques for C ACCU 2006 © Schalk W. Cronjé
  • 45. Strategies for C ● C has nowhere near the power and flexibility of C++, but basic principles remain the same – Configure generic components using generated macros – Aim for zero cyclomatic-complexity in the macros ● Use indirect naming in order to attempt a bit of compile-time safety – Hide void* and varargs from programmer ● Use types as a strategy for compile-time validation – C does not place parameter types in symbols – Type manipulation will not create excessive symbol tables ACCU 2006 © Schalk W. Cronjé
  • 46. Example #3: C Configuration system /* Public interface via macros */ #define CONFIG_TYPE( CFGATTR ) ..... #define CONFIG_TOKEN( CFGATTR,EXTRA ) .... #define CONFIG_GET( CFGATTR,VAR ) .... CONFIG_TYPE(NetworkPort) v; printf( "The network port we'll use is " CONFIG_TOKEN(NetworkPort,"") "n", * CONFIG_GET(NetworkPort,v) ); ACCU 2006 © Schalk W. Cronjé
  • 47. Example #3: Implementation void* config_get__( char const* pName_, size_t varsize_, void * var_, ... ); Pass in order: •Function for setting default •Pointer to default value •Function for setting bounds •Pointer to minimum value •Pointer to maximum value ACCU 2006 © Schalk W. Cronjé
  • 48. Example #3: Generic Macros #define CONFIG_TYPE( CFGATTR ) AUTOGENCFG_TYPE_##CFGATTR #define CONFIG_TOKEN( CFGATTR,EXTRA ) "%" EXTRA AUTOGENCFG_TOKEN_##CFGATTR #define CONFIG_GET( CFGATTR,VAR ) ( CONFIG_TYPE(CFGATTR) *) config_get__( AUTOGENCFG_NAME_##CFGATTR, sizeof( CONFIG_TYPE(CFGATTR) ), & VAR, Hide implementation AUTOGENCFG_DEFAULTF_##CFGATTR, inside macro AUTOGENCFG_DEFAULT_##CFGATTR, AUTOGENCFG_BOUNDF_##CFGATTR, AUTOGENCFG_MIN_##CFGATTR, AUTOGENCFG_MAX_##CFGATTR ) ACCU 2006 © Schalk W. Cronjé
  • 49. Example #3: Generated Macros #define AUTOGENCFG_TYPE_NetworkPort uint16_t #define AUTOGENCFG_TOKEN_NetworkPort "hu" #define AUTOGENCFG_NAME_NetworkPort "sys.network.port" #define AUTOGENCFG_DEFAULTF_NetworkPort &config_set_default__ #define AUTOGENCFG_DEFAULT_NetworkPort 1234 #define AUTOGENCFG_BOUNDF_NetworkPort &config_bound_ushort__ #define AUTOGENCFG_MIN_NetworkPort 1024 #define AUTOGENCFG_MAX_NetworkPort 65535 ACCU 2006 © Schalk W. Cronjé
  • 50. Updated ADT Lookup Table <types> <type adt="uint16"> <cpp type="uint16_t" quoted="no"/> <c type="uint16_t" quoted="no"/> </type> <type adt="string"> <cpp type="std::string" quoted="yes"/> <c type="const char*" quoted="yes"/> </type> <!-- c/@type: What type to use on a C system c/@quoted: Whether to quote the type in a macro definition --> </types> ACCU 2006 © Schalk W. Cronjé
  • 51. Example #4: C Logging System /* Public interface via macro */ #define LOG_IT( LOGNAME,ACTION,TEXT ) .... // Valid rule LOG_IT( MAJOR_PROBLEM,GO_BUY, "Bought some Hoegaarden" ); // Invalid combination – fails to compile LOG_IT( MAJOR_PROBLEM,CALL_SECURITY, "Bought some Hoegaarden" ); ACCU 2006 © Schalk W. Cronjé
  • 52. Example #4: Generated C /* Events and as macros */ #define AUTOGENLOG_ID_MINOR_FAILURE 10 #define AUTOGENLOG_ID_MAJOR_PROBLEM 20 #define AUTOGENLOG_ID_GENERAL_PANIC 30 #define AUTOGENLOG_ACTION_GO_BUY 1 #define AUTOGENLOG_ACTION_CALL_SECURITY 2 #define AUTOGENLOG_ACTION_MAKE_ANNOUNCEMENT 3 /* Valid combinations as union */ union AUTOGENLOG_ACTIONS_MAJOR_PROBLEM { unsigned long GO_BUY; unsigned long MAKE_ANNOUNCEMENT; }; ACCU 2006 © Schalk W. Cronjé
  • 53. Example #4: C Implementation /* Implementation function Internals left as exercise for the reader */ void log_it__( unsigned long id, Use union member to unsigned long action, perform compile-time validation const char* text ); #define LOG_IT( LOGNAME,ACTION,TEXT ) do { auto union AUTOGENLOG_ACTIONS_##LOGNAME x; x. ACTION = AUTOGENLOG_ACTION_##ACTION; log_it__( AUTOGENLOG_ID_##LOGNAME,x. ACTION,TEXT); } while(0) ACCU 2006 © Schalk W. Cronjé
  • 54. Preventing C Code-bloat ● Keep generated code in macros and type definitions where possible. ● Keep executable code inside macros simplistic and to a minimum ● Rely on compiler optimisation for where duplication cannot be avoided ● Cleanly separate common code into testable functions ACCU 2006 © Schalk W. Cronjé
  • 55. Techniques for Scripting / Dynamic Languages ACCU 2006 © Schalk W. Cronjé
  • 56. Dispelling Myths about Reflection ● Myth #1: I don't need GP because language X has reflection ● Myth #2: I don't need reflection because I am using GP ● Fact: GP maps the domain knowledge, captured in a non-programming language, into a programming language. – If reflection is the most effective way of doing this in language X, then it should be used. ACCU 2006 © Schalk W. Cronjé
  • 57. Problems with Build-time Validation ● Early validation at build-time is not always trivial ● Perl can sometimes use -c switch ● JavaScript is difficult ● Sometimes validation has to be pushed out to unit tests – Should never require system testing to provide the validation ACCU 2006 © Schalk W. Cronjé
  • 58. Example #5: JavaScript Configuration // For writing and reading configuration files function get_config( CFGNAME ); function get_config_text( CFGNAME ); function set_config( CFGNAME, new_value ); document.write( get_config_text(NetworkPort), ": ", get_config(NetworkPort) ); Will display text description from metadata (suitably localised) ACCU 2006 © Schalk W. Cronjé
  • 59. Example #5: Generated JS Traits // Autogenerated 'traits' var NetworkPort = new Object; NetworkPort.min = 1024; NetworkPort.max = 65535; NetworkPort.defaultvalue= 1234; NetworkPort.path= "subsystem.network.port"; // Validate functions are first-class variables NetworkPort.validate= validate_integral; // Localised text setting NetworkPort.descr.en = "Unrestricted port on which a service can be started"; ACCU 2006 © Schalk W. Cronjé
  • 60. Example #5: JS Config Read // Reads a variable from a path in a config file // Implementation is system-dependant function get_from_config_file( Path ) { /* ... */ } function get_config( CFGNAME ) { var tmp = get_from_config_file( CFGNAME.path ); if( tmp == null ) return CFGNAME.defaultvalue; else return tmp; } ACCU 2006 © Schalk W. Cronjé
  • 61. Example #5: JS Config Write // Writes a new value to the path in a config file // Implementation is system-dependant function set_in_config_file( Path,Value ) {/* .... */} function set_config( CFGNAME, new_value ) { if(typeof (new_value) != typeof (CFGNAME.defaultvalue) ) throw "Invalid Type Applied"; CFGNAME.validate(new_value,CFGNAME.min,CFGNAME.max); set_in_config_file( CFGNAME.path, new_value); } ACCU 2006 © Schalk W. Cronjé
  • 62. Updated ADT Lookup Table <types> <type adt="uint16"> ... <js type="Number" quoted="no"/> </type> <type adt=”string”> ... <js type="String" quoted="yes"/> </type> <!-- js/@type: What type to use in JavaScript js/@quoted: Whether to quote the type initialisation --> </types> ACCU 2006 © Schalk W. Cronjé
  • 63. Updated ADT Lookup Table <types> (no types) <type adt="uint16"> ... <js quoted="no"/> </type> <type adt="string"> ... <js quoted="yes"/> </type> <!-- js/@quoted: Whether to quote the type initialisation --> </types> ACCU 2006 © Schalk W. Cronjé
  • 64. The Bigger Picture ACCU 2006 © Schalk W. Cronjé
  • 65. Multiple Systems ● Examples until now have shown the GP steps for a configuration system and a logging system. ● The next step is to apply these to three systems: – System 1 uses XML files for configuration and sends logs to syslog. – System2 uses INI files, and sends logs to NT Evlog – System 3 keeps configuration in a binary format (read-only) and sends logs via SNMP. ACCU 2006 © Schalk W. Cronjé
  • 66. Example Product Metadata <Products> <System id=”1”> <Config type=”xml”/> <Logging type=”syslog”/> <Functionality> ... <Functionality> </System> <System id=”2”> <Config type=”ini”/> <Logging type=”ntevlog”/> <Functionality> ... <Functionality> </System> </Products> ACCU 2006 © Schalk W. Cronjé
  • 67. Building Multiple Systems ● Four generators can be applied to this product metadata. – Two of them we have already seen – These will generate configurations and logging aspects ● Another generator looks at logging and configurations and adds the appropriate subsystems. ● A fourth generator looks at the functionality and loads up all of the functional classes for the system – A creative exercise for the reader … ACCU 2006 © Schalk W. Cronjé
  • 68. Integration ● Many modern systems are multi-language / multi- platform ● These techniques extend easily into other programming languages / development environments ● The same configuration knowledge remains the driver ● Localisation data can be generated in various formats ● Parts of technical documents can also be generated. ACCU 2006 © Schalk W. Cronjé
  • 69. Bad smells ● The unit tests are generated – How can you verify that the generated tests is correct? – Generating test inputs & outputs are acceptable ● There is business logic in the generators – The DSL is probably incorrect ● The generated code is edited before usage – Artefacts are not templates ● Every build takes very long – Dependency checking must be improved ACCU 2006 © Schalk W. Cronjé
  • 70. Further Reading ● www.program-transformation.org ● www.generative-programming.org ● www.codegeneration.net ● research.microsoft.com ● www.martinfowler.com ACCU 2006 © Schalk W. Cronjé