=============
DSL challenge
=============

.. contents:: Table of contents

------------
Introduction
------------

.. include:: ./dsl_challenge_introduction.rest

-------------------
Py++ user interface
-------------------

I will use the following C++ code as an example:

.. code-block:: C++

  namespace geometry{
      struct Point{
        Point();
        Point(int x, int y);
        Point( const Point& );

        Point* create_new(){ return *this; }

        int x, y;
        int private_data;
      };
  }

In order to export this class, we need:

1. to set "call policies" to ``create_new`` member function

2. to exclude ``private_data`` member variable

3. to rename ``x`` and ``y`` to ``X`` and ``Y``

Today, in order to configure this class, the user has to write the following code:

.. code-block:: Python

  mb = module_builder_t( ... )
  Point = mb.class_( 'Point' )
  Point.member_function( 'create_new' ).call_policies = ...
  Point.member_variable( 'private_data' ).exclude()
  Point.member_variable( 'x' ).rename( 'X' )
  Point.member_variable( 'Y' ).rename( 'Y' )
  #or
  for mvar in Point.member_variables():
      mvar.rename( mvar.name.upper() )

If class ``Point`` is not unique, than user will have to write a little bit
different code:

.. code-block:: Python

  Point = mb.global_ns.namespace('geometry').class( 'Point' )

The current approach is pretty readable and simple. The drawbacks of this approach
are:

1. before the user starts with `Py++`_ he is forced to read a lot of documentation
2. verbosity - in order to complete the task, the user have to write "a lot" of
   code

------------------
Better API (B-API)
------------------

.. code-block:: Python

  mb = module_builder_t( ... )
  Point = mb.module.geometry.Point
  Point.create_new.call_policies = ...
  Point.private_data.exclude()
  Point.x.rename( 'X' )
  Point.y.rename( 'Y' )

What you see here is DSL!

----------
Comparison
----------

I don't argue, that the second way is better. I would like to expose you to few
problems it has.

Rule based approach
-------------------

B-API does not allow to use "rule based" approach and to work on the whole
declarations tree!

Special syntax
--------------

Special syntax should be introduce to support

* template instantiations

  B-API does not work for template instantiated classes and functions. If we change
  class ``Point`` to be template, the special syntax should be introduced:

    .. code-block:: C++

     template < class Numeric >
     struct Point{
         ...
     };

    .. code-block:: Python

       PointTmpl = mb.module.template('Point')
       Point = PointTmpl( 'int' )

  This is a trivial example, which is why it looks great. Consider the following class:

    .. code-block:: C++

       template< class String, class Allocator >
       class regex{ ... }

  The code the user will need to write is:

    .. code-block:: Python

       regex_tmpl = mb.module.geometry.template( 'regex' )
       #white spaces and scope resolution( :: ) are important
       regex_std_string = regex_tmpl(
             '::std::basic_string<char,std::char_traits<char>,std::allocator<char> >'
           , '::std::allocator<char>' )

  Using current `Py++`_ interface the user can get reference to the class
  instantiation in one line of code:

    .. code-block:: Python

       regex_std_string = mb.class_(
          lambda decl: decl.name.startswith( 'regex' ) and 'wchar_t' not in decl.name )

* overloaded functions resolution

  There are use cases, when overloaded functions should be treated differently.
  It is not possible to distinguish between different functions, using B-API syntax.

* C++ operators

  They also require special syntax.

Readability counts
------------------

It is not clear from the script, on how many and on what declarations
configuration is applied. It is possible to introduce a bug. Using current `Py++`_
API the user always states, whether he expects a declaration to be unique or not
and its type.

Full name
---------

Using B-API the user is forced to write full declaration name, otherwise he faces
the following problem:

  .. code-block:: Python

     Point = mb.module.Point

Lets analyze what the ``Point`` value:

1. It could be reference to a declaration, that has name "Point" and it is
   defined under global namespace.

2. It could be a set of declarations that has "Point" as a name from all classes
   and namespaces. In our case it will contain at lease reference to class
   "Point" declaration and its constructors.

   There are a lot of use cases, when the user has to add some code to the class:

   .. code-block:: Python

      Point.add_registration_code( ... )

   Constructor declaration does not define ``add_registration_code`` method.
   According to Python rules: "Errors should never pass silently", exception
   should be raised.

Another Python rule says: "In the face of ambiguity, refuse the temptation to guess".

-----------
Action item
-----------

I think, it should be obvious to you, that we cannot drop current `Py++`_ user
interface. The only solution I see, is to build B-API on top of it. The reason
the project does not have B-API is simple. I don't feel comfortable to introduce
it, while I am aware to all these problems.

The title of this section should be **Your action item** :-). I will be glad
to implement B-API, if we can solve all the problems. Consider to contribute your
experience and knowledge to fix the situation. I am sure together we will build
very powerful and easy to use code generator.



.. _`Py++` : ./../pyplusplus.html
.. _`Boost.Python`: http://www.boost.org/libs/python/doc/index.html
.. _`Python`: http://www.python.org
.. _`GCC-XML`: http://www.gccxml.org

