Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r48914 - trunk/libs/proto/doc
From: eric_at_[hidden]
Date: 2008-09-21 16:48:08


Author: eric_niebler
Date: 2008-09-21 16:48:06 EDT (Sun, 21 Sep 2008)
New Revision: 48914
URL: http://svn.boost.org/trac/boost/changeset/48914

Log:
document as_expr(), as_child(), literal<>, lit() and BOOST_PROTO_EXTENDS() and friends
Text files modified:
   trunk/libs/proto/doc/calculator.qbk | 2
   trunk/libs/proto/doc/construction.qbk | 52 ++++++++++++++++++
   trunk/libs/proto/doc/extensibility.qbk | 110 ++++++++++++++++++++++++++++++++++++---
   trunk/libs/proto/doc/glossary.qbk | 8 ++
   trunk/libs/proto/doc/grammars.qbk | 8 ++
   trunk/libs/proto/doc/hello_world.qbk | 1
   trunk/libs/proto/doc/implementation.qbk | 8 +-
   trunk/libs/proto/doc/preface.qbk | 29 ++-------
   8 files changed, 182 insertions(+), 36 deletions(-)

Modified: trunk/libs/proto/doc/calculator.qbk
==============================================================================
--- trunk/libs/proto/doc/calculator.qbk (original)
+++ trunk/libs/proto/doc/calculator.qbk 2008-09-21 16:48:06 EDT (Sun, 21 Sep 2008)
@@ -54,7 +54,7 @@
     (_2 - _1) / _2 * 100;
 
 This creates an expression tree with a node for each operator. The type of the
-resulting object is large and complex, but we are not terribly interested in it.
+resulting object is large and complex, but we are not terribly interested in it right now.
 
 So far, the object is just a tree representing the expression. It has no
 behavior. In particular, it is not yet a calculator. Below we'll see how

Modified: trunk/libs/proto/doc/construction.qbk
==============================================================================
--- trunk/libs/proto/doc/construction.qbk (original)
+++ trunk/libs/proto/doc/construction.qbk 2008-09-21 16:48:06 EDT (Sun, 21 Sep 2008)
@@ -144,7 +144,57 @@
 [heading Making Terminals]
 [/=======================]
 
-TODO: describe as_expr(), as_arg(), literal<> and lit().
+Proto's expression-building operator overloads are only considered when at least one operand is itself a Proto expression. We've seen how to define Protofied terminals with _terminal_, but that method can be a little awkward at times. Proto provides an easier-to-use wrapper for literals that can be used to construct Protofied terminal expressions. It's called _literal_.
+
+ // Define a literal integer Proto expression.
+ proto::literal<int> i = 0;
+
+ // Proto literals are really just Proto terminal expressions.
+ // For example, this build a proto expression template:
+ i + 1;
+
+There is also a _lit_ function for constructing a _literal_ in-place. The above expression can simply be written as:
+
+ // proto::lit(0) creates an integer terminal expression
+ proto::lit(0) + 1;
+
+Sometimes you might want to Protofy an object, but only if it has not already been Protofied. This is especially common when writing lazy functions for your DSEL. For these situations there is _as_expr_ and _as_child_. Imagine that for the calculator DSEL described in the Getting Started guide that you wanted to define a `pow()` function that lazily raises its argument to an integral exponent. You would want expressions like `pow<2>(_1)` to work (where `_1` is an argument placeholder), and you also want to allow `pow<2>(42)`. In the first case, `_1` is already a Proto expression type, but in the second, `42` is not. Here's how you would do it.
+
+ // Define a pow_fun function object
+ template<int Exp>
+ struct pow_fun
+ {
+ typedef double result_type;
+ double operator()(double d) const
+ {
+ return std::pow(d, Exp);
+ }
+ };
+
+ // Define a lazy pow() function for the calculator DSEL. Use
+ // proto::as_child() to Protofying the argument, but only if it
+ // is not a Proto expression type to begin with!
+ template<int Exp, typename Arg>
+ typename proto::function<
+ typename proto::terminal<pow_fun<Exp> >::type
+ , typename proto::result_of::as_child<Arg const>::type
+ >::type
+ pow(Arg const &arg)
+ {
+ typedef
+ typename proto::function<
+ typename proto::terminal<pow_fun<Exp> >::type
+ , typename proto::result_of::as_child<Arg const>::type
+ >::type
+ result_type;
+
+ result_type result = {{{}}, proto::as_child(arg)};
+ return result;
+ }
+
+In the above, `pow()` uses _as_child_ to Protofy its argument, but only if the argument is not already a Proto expression. When passed a Proto expression, _as_child_ returns it unmolested. When passed a non-Proto object, it is turned into a Proto expression by wrapping it in a Proto terminal /by reference/. So for instance, the expression created by `pow<2>(42)` holds `42` by const reference.
+
+If you don't want the resulting terminal expression to hold its value by reference, you can use _as_expr_ instead. _as_expr_ behaves exactly as _as_child_ except that, when passed a non-Proto object, _as_expr_ wraps it in a Proto terminal expression /by value/.
 
 [/================================]
 [heading Building Expression Trees]

Modified: trunk/libs/proto/doc/extensibility.qbk
==============================================================================
--- trunk/libs/proto/doc/extensibility.qbk (original)
+++ trunk/libs/proto/doc/extensibility.qbk 2008-09-21 16:48:06 EDT (Sun, 21 Sep 2008)
@@ -80,9 +80,10 @@
         // assignment operator hides the extends<>::operator=
         using base_type::operator =;
 
+ typedef double result_type;
+
         // Hide base_type::operator() by defining our own which
         // evaluates the calculator expression with a calculator context.
- typedef double result_type;
         result_type operator()( double d1 = 0.0, double d2 = 0.0 ) const
         {
             // As defined in the Hello Calculator section.
@@ -127,8 +128,95 @@
 
 [heading Retaining POD-ness with [^BOOST_PROTO_EXTENDS()]]
 
-TODO Describe the `BOOST_PROTO_EXTENDS()` family of macros.
+To use _extends_, your extension type must derive from _extends_. Unfortunately, that means that your extension type is no longer POD and its instances cannot be /statically initialized/. (See the [link boost_proto.appendices.rationale.static_initialization Static
+Initialization] section in the [link boost_proto.appendices.rationale Rationale]
+appendix for why this matters.) In particular, as defined above, the global placeholder objects `_1` and `_2` will need to be initialized at runtime, which could lead to subtle order of initialization bugs.
+
+There is another way to make an expression extension that doesn't sacrifice POD-ness : the `BOOST_PROTO_EXTENDS()` macro. You can use it much like you use _extends_. We can use `BOOST_PROTO_EXTENDS()` to keep `calculator<>` a POD and our placeholders statically initialized.
+
+ // The calculator<> expression wrapper makes expressions
+ // function objects.
+ template< typename Expr >
+ struct calculator
+ {
+ // Use BOOST_PROTO_EXTENDS() instead of proto::extends<> to
+ // make this type a Proto expression extension.
+ BOOST_PROTO_EXTENDS(Expr, calculator<Expr>, calculator_domain)
+
+ typedef double result_type;
+
+ result_type operator()( double d1 = 0.0, double d2 = 0.0 ) const
+ {
+ /* ... as before ... */
+ }
+ };
+
+With the new `calculator<>` type, we can redefine our placeholders to be statically initialized:
+
+ calculator< proto::terminal< placeholder<0> >::type > const _1 = {{{}}};
+ calculator< proto::terminal< placeholder<1> >::type > const _2 = {{{}}};
+
+We need to make one additional small change to accomodate the POD-ness of our expression extension, which we'll describe below in the section on expression generators.
+
+What does `BOOST_PROTO_EXTENDS()` do? It defines a data member of expression type being extended; some nested typedefs that Proto requires; `operator=`, `operator[]` and `operator()` overloads for building expression templates; and a nested `result<>` template for calculating the return type of `operator()`. In this case, however, the `operator()` overloads and the `result<>` template are not needed because we are defining our own `operator()` in the `calculator<>` type. Proto provides additional macros for finer control over which member functions are defined. We could improve our `calculator<>` type as follows:
+
+ // The calculator<> expression wrapper makes expressions
+ // function objects.
+ template< typename Expr >
+ struct calculator
+ {
+ // Use BOOST_PROTO_BASIC_EXTENDS() instead of proto::extends<> to
+ // make this type a Proto expression extension:
+ BOOST_PROTO_BASIC_EXTENDS(Expr, calculator<Expr>, calculator_domain)
+
+ // Define operator[] to build expression templates:
+ BOOST_PROTO_EXTENDS_SUBSCRIPT()
+
+ // Define operator= to build expression templates:
+ BOOST_PROTO_EXTENDS_ASSIGN()
+
+ typedef double result_type;
+
+ result_type operator()( double d1 = 0.0, double d2 = 0.0 ) const
+ {
+ /* ... as before ... */
+ }
+ };
+
+Notice that we are now using `BOOST_PROTO_BASIC_EXTENDS()` instead of `BOOST_PROTO_EXTENDS()`. This just adds the data member and the nested typedefs but not any of the overloaded operators. Those are added separately with `BOOST_PROTO_EXTENDS_ASSIGN()` and `BOOST_PROTO_EXTENDS_SUBSCRIPT()`. We are leaving out the function call operator and the nested `result<>` tempate that could have been defined with Proto's `BOOST_PROTO_EXTENDS_FUNCTION()` macro.
+
+In summary, here are the macros you can use to define expression extensions, and a brief description of each.
 
+[def __expression__ [~expression]]
+[def __extension__ [~extension]]
+[def __domain__ [~domain]]
+
+[table Expression Extension Macros
+ [[Macro]
+ [Purpose]]
+ [[``BOOST_PROTO_BASIC_EXTENDS(
+ __expression__
+ , __extension__
+ , __domain__
+)``]
+ [Defines a data member of type `__expression__` and some nested typedefs that Proto requires.]]
+ [[`BOOST_PROTO_EXTENDS_ASSIGN()`]
+ [Defines `operator=`. Only valid when preceeded by `BOOST_PROTO_BASIC_EXTENDS()`.]]
+ [[`BOOST_PROTO_EXTENDS_SUBSCRIPT()`]
+ [Defines `operator[]`. Only valid when preceeded by `BOOST_PROTO_BASIC_EXTENDS()`.]]
+ [[`BOOST_PROTO_EXTENDS_FUNCTION()`]
+ [Defines `operator()` and a nested `result<>` template for return type calculation. Only valid when preceeded by `BOOST_PROTO_BASIC_EXTENDS()`.]]
+ [[``BOOST_PROTO_EXTENDS(
+ __expression__
+ , __extension__
+ , __domain__
+)``]
+ [Equivalent to:``
+ BOOST_PROTO_BASIC_EXTENDS(__expression__, __extension__, __domain__)
+ BOOST_PROTO_EXTENDS_ASSIGN()
+ BOOST_PROTO_EXTENDS_SUBSCRIPT()
+ BOOST_PROTO_EXTENDS_FUNCTION()``]]
+]
 
 [endsect]
 
@@ -151,14 +239,18 @@
 
 The first template parameter to `proto::domain<>` is the generator. "Generator" is just a fancy name for a function object that accepts an expression and does something to it. `proto::generator<>` is a very simple one --- it wraps an expression in the wrapper you specify. `proto::domain<>` inherits from its generator parameter, so all domains are themselves function objects.
 
-[def __domain__ [~Domain]]
+If we used `BOOST_PROTO_EXTENDS()` to keep our expression extension type POD, then we need to use `proto::pod_generatro<>` instead of `proto::generator<>`, as follows:
+
+ // If calculator<> uses BOOST_PROTO_EXTENDS() instead of
+ // use proto::extends<>, use proto::pod_generator<> instead
+ // of proto::generator<>.
+ struct calculator_domain
+ : proto::domain< proto::pod_generator< calculator > >
+ {};
+
+[def __Domain__ [~Domain]]
 
-After Proto has calculated a new expression type, it checks the domains of the
-child expressions. They must match. Assuming they do, Proto creates the new
-expression and passes it to `__domain__::operator()` for any additional processing.
-If we don't specify a generator, the new expression gets passed through unchanged.
-But since we've specified a generator above, `calculator_domain::operator()`
-returns `calculator<>` objects.
+After Proto has calculated a new expression type, it checks the domains of the child expressions. They must match. Assuming they do, Proto creates the new expression and passes it to `__Domain__::operator()` for any additional processing. If we don't specify a generator, the new expression gets passed through unchanged. But since we've specified a generator above, `calculator_domain::operator()` returns `calculator<>` objects.
 
 Now we can use calculator expressions as function objects to STL algorithms, as
 follows:

Modified: trunk/libs/proto/doc/glossary.qbk
==============================================================================
--- trunk/libs/proto/doc/glossary.qbk (original)
+++ trunk/libs/proto/doc/glossary.qbk 2008-09-21 16:48:06 EDT (Sun, 21 Sep 2008)
@@ -19,6 +19,14 @@
        `proto::is_callable<R>::value` is `true`. `R` is treated as a polymorphic
        function object and the arguments are treated as transforms that yield the
        arguments to the function object.] ]
+ [ [ [anchor context] context]
+ [In Proto, the term /context/ refers to an object that can be passed, along
+ with an expression to evaluate, to the `proto::eval()` function. The context
+ determines how the expression is evaluated. All context structs define a
+ nested `eval<>` template that, when instantiated with a node tag type (e.g.,
+ `proto::tag::plus`), is a binary polymorphic function object that accepts an
+ expression of that type and the context object. In this way, contexts
+ associate behaviors with expression nodes.] ]
   [ [ [anchor domain] domain]
       [In Proto, the term /domain/ refers to a type that associates expressions
        within that domain with a /generator/ for that domain and optionally a

Modified: trunk/libs/proto/doc/grammars.qbk
==============================================================================
--- trunk/libs/proto/doc/grammars.qbk (original)
+++ trunk/libs/proto/doc/grammars.qbk 2008-09-21 16:48:06 EDT (Sun, 21 Sep 2008)
@@ -297,6 +297,14 @@
 
 [endsect]
 
+[/==========================]
+[section:switch [^switch_<>]]
+[/==========================]
+
+TODO document proto::switch_<>
+
+[endsect]
+
 [/==================================]
 [section Matching Vararg Expressions]
 [/==================================]

Modified: trunk/libs/proto/doc/hello_world.qbk
==============================================================================
--- trunk/libs/proto/doc/hello_world.qbk (original)
+++ trunk/libs/proto/doc/hello_world.qbk 2008-09-21 16:48:06 EDT (Sun, 21 Sep 2008)
@@ -14,7 +14,6 @@
 
     #include <iostream>
     #include <boost/proto/proto.hpp>
- #include <boost/proto/context.hpp>
     #include <boost/typeof/std/ostream.hpp>
     using namespace boost;
 

Modified: trunk/libs/proto/doc/implementation.qbk
==============================================================================
--- trunk/libs/proto/doc/implementation.qbk (original)
+++ trunk/libs/proto/doc/implementation.qbk 2008-09-21 16:48:06 EDT (Sun, 21 Sep 2008)
@@ -163,10 +163,12 @@
 
 [endsect]
 
-[section:ppmp_vs_tmp Avoiding Template Instiations With The Preprocessor]
+[/
+ [section:ppmp_vs_tmp Avoiding Template Instiations With The Preprocessor]
 
-TODO
+ TODO
 
-[endsect]
+ [endsect]
+]
 
 [endsect]

Modified: trunk/libs/proto/doc/preface.qbk
==============================================================================
--- trunk/libs/proto/doc/preface.qbk (original)
+++ trunk/libs/proto/doc/preface.qbk 2008-09-21 16:48:06 EDT (Sun, 21 Sep 2008)
@@ -13,10 +13,7 @@
 
 [heading Description]
 
-Proto is a framework for building Domain Specific Embedded Languages
-in C++. It provides tools for constructing, type-checking, transforming and
-executing ['expression templates][footnote See
-[@http://www.osl.iu.edu/~tveldhui/papers/Expression-Templates/exprtmpl.html Expression Templates]].
+Proto is a framework for building Domain Specific Embedded Languages in C++. It provides tools for constructing, type-checking, transforming and executing ['expression templates][footnote See [@http://www.osl.iu.edu/~tveldhui/papers/Expression-Templates/exprtmpl.html Expression Templates]].
 More specifically, Proto provides:
 
 * An expression tree data structure.
@@ -28,21 +25,7 @@
 
 [heading Motivation]
 
-Expression Templates are an advanced technique that C++ library developers use
-to define embedded mini-languages that target specific problem domains. The
-technique has been used to create hyper-efficient and easy-to-use libraries
-for linear algebra as well as to define C++ parser generators with a readable
-syntax. But developing such a library involves writing an inordinate amount of
-unreadable and unmaintainable template mumbo-jumbo. Boost.Proto eases the
-development of [link boost_proto.users_guide.glossary.dsel domain-specific embedded
-languages (DSELs)]. Use Proto to define the primitives of your mini-language and
-let Proto handle the operator overloading and the construction of the expression
-parse tree. Immediately evaluate the expression tree by passing it a function
-object. Or transform the expression tree by defining the grammar of your mini-
-language, decoratedwith an assortment of tree transforms provided by Proto or
-defined by you. Then use the grammar to give your users short and readable syntax
-errors for invalid expressions! No more mumbo-jumbo -- an expression template
-library developed with Proto is declarative and readable.
+Expression Templates are an advanced technique that C++ library developers use to define embedded mini-languages that target specific problem domains. The technique has been used to create efficient and easy-to-use libraries for linear algebra as well as to define C++ parser generators with a readable syntax. But developing such a library involves writing an inordinate amount of unreadable and unmaintainable template mumbo-jumbo. Boost.Proto eases the development of [link boost_proto.users_guide.glossary.dsel domain-specific embedded languages (DSELs)]. Use Proto to define the primitives of your mini-language and let Proto handle the operator overloading and the construction of the expression parse tree. Immediately evaluate the expression tree by passing it a function object. Or transform the expression tree by defining the grammar of your mini-language, decoratedwith an assortment of tree transforms provided by Proto or defined by you. Then use the grammar to give your users short and readable syntax erro
rs for invalid expressions! No more mumbo-jumbo -- an expression template library developed with Proto is declarative and readable.
 
 In short, Proto is a DSEL for defining DSELs.
 
@@ -52,7 +35,7 @@
 
 This documentation makes use of the following naming and formatting conventions.
 
-* Code is in `fixed with font` and is syntax-highlighted.
+* Code is in `fixed width font` and is syntax-highlighted.
 * Replaceable text that you will need to supply is in [~italics].
 * If a name refers to a free function, it is specified like this:
   `free_function()`; that is, it is in code font and its name is followed by `()`
@@ -75,10 +58,14 @@
     // Include all of Proto
     #include <boost/proto/proto.hpp>
 
- // Create a namespace alias for boost::proto
+ // Create some namespace aliases
+ namespace mpl = boost::mpl;
+ namespace fusion = boost::fusion;
     namespace proto = boost::proto;
 
     // Allow unqualified use of Proto's wildcard pattern
     using proto::_;
 
+In addition to the above, `mpl` is a namespace alias for `boost::mpl`, and `fusion` is an alias for `boost::fusion`.
+
 [endsect]


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk