1[section Expressions] 2 3_yap_ consists of expressions and functions that operate on them. A function 4that takes an expression will accept any type that models the _Expr_ concept. 5 6For a type `T` to model the _Expr_ concept, `T` must contain at least an 7_kind_ (terminal, plus-operation, etc.) and a _tuple_ of values. That's it. 8 9[note The _tuple_ of values is constrained, based on the kind of the 10expression; see the full _Expr_ documentation for details.] 11 12Here's an example of an expression: 13 14[minimal_template] 15 16That's a template that models _ExprTmpl_. Instantiated with the proper 17template parameters, it produces _Exprs_. 18 19Ok, so it's not that interesting by itself _emdash_ `minimal_expr` has no 20operations defined for it. But we can still use it with the _yap_ functions 21that take an _Expr_. Let's make a _yap_ plus-expression manually: 22 23[minimal_template_manual_construction] 24 25If we evaluate it using _eval_, it does what you would expect: 26 27[minimal_template_evaluation] 28 29One more thing. It is important to remember that _yap_ expressions are 30all-lazy, all the time. There is no auto-evaluation of a _yap_ expression 31like there is with normal C++ expressions. If you want your expressions to be 32evaluated, you must call _eval_, or define non-lazy operations that force 33evaluation where and when you want it. This last approach is usually the 34right one, and there are lots of examples of how to do this in the _examples_ 35section. In particular, checkout the _lazy_vector_ and _tarray_ examples. 36 37[endsect] 38 39 40[section Mix-and-Match Expression Templates] 41 42Because _yap_ operates on _Exprs_, it is possible to mix and match _Exprs_ 43that are instantiations of different templates. 44 45Here's why that's important. Say we have two types in a library. `S` is a 46string type, and `M` is a matrix type. In the code here, `s` and `m` are 47objects of types `S` and `M` respectively. Say we also have typical operator 48overloads for these types, so `m * m` and `s[0]` are well-formed expressions, 49but `m[0]` and `s * s` are not. 50 51To use these with _yap_ I might write an expression template for each: 52 53 template <...> 54 struct m_expr 55 { 56 // ... 57 }; 58 59 BOOST_YAP_USER_BINARY_OPERATOR(times, m_expr, m_expr) 60 61 template <...> 62 struct s_expr 63 { 64 // ... 65 BOOST_YAP_USER_SUBSCRIPT_OPERATOR(::s_expr) 66 }; 67 68With this, I might write a _yap_ expression like: 69 70 some_expr_producing_func(S("my_matrix")) * some_matrix 71 72I can transform this expression however I like, and do not have to worry about 73the fact that it contains expressions instantiated from different templates. 74 75If _yap_ required an expression to be instantiated from a single expression 76template `expr<>`, `expr<>` would have to have both operators. This means 77that all of a sudden `s * s` and `m[0]` would be well-formed expressions 78within a _yap_ expression, but *not* for the real types `S` and `M` 79respectively. That would be super weird. 80 81[endsect] 82 83 84[section Kinds of Expressions] 85 86Most of the expression kinds are the overloadable operators (`operator!()`, 87`operator<<=()`, etc.), See _kind_ for the full list. 88 89There are three special kinds of expressions: 90 91[variablelist 92 [[_terminal_] [A terminal contains a non-Expression value, and represents a leaf-node in an 93expression tree. A terminal may have a _placeholder_ value, in which case it acts as a placeholder. ]] 94 [[_if_else_] [An `if_else` expression is analogous to the C++ ternary operator (`?:`). It's up to you to make sure that the conditional expression given to `if_else` can be converted to `bool`; _yap_ does not check this.]] 95 [[_expr_ref_] [An `expr_ref` expression is one that acts as a (possibly `const`) lvalue reference to another expression. It exists to prevent unnecessary copies of expressions.]] 96] 97 98[endsect] 99 100 101[section Operators] 102 103Let's see an expression template type with some operators: 104 105[lazy_vector_decl] 106 107Those macros are used to define operator overloads that return _Exprs_. As 108shown here, that sort of operator can be mixed with normal, non-lazy ones 109_emdash_ the `operator[]` is a normal eager function. 110 111Use of the macros is not necessary (you can write your own operators that 112return _Exprs_ if you like), but it is suitable 99% of the time. 113 114Making the operators easy to define like this allows you to define custom 115expression templates that have only the operators defined that are appropriate 116for your use case. 117 118Detailed documentation on all the available macros can be found later in the 119_operator_macros_ section. 120 121[endsect] 122 123 124[section Transforming Expressions] 125 126Transformations in _yap_ are done using the _xform_ function. 127 128Let's take another look at the example expression from the intro: 129 130[$yap/img/expr.png] 131 132Consider a call to _xform_, operating on that expression: 133 134 auto result = boost::yap::transform(expr, xform); 135 136_yap_'s _xform_ first looks at the top level expression, which in this case is 137a `+` expression. If the transform object `xform` matches the `+` expression, 138_xform_ is done; it just returns `xform(expr)`. If `xform` does not match the 139`+` expression, _xform_ transforms all its operands (which for `operator+()` 140is just the left and right operands), and returns a new `+` expression with 141those transformed operands. What I mean by "match" is covered in detail 142below. 143 144The overall effect of this is that _xform_ effectively copies an `expr` node 145that *does not* match `xform`, and returns a transformed node for an `expr` 146node that *does* match `xform`. 147 148_xform_ can also take multiple transform objects. If you call it with N 149transform objects, it will attempt to match each of the N transforms to a 150given expression, one at a time and in their given order. Only if no 151transform matches an expression does the copy-and-recurse behavior kick in. 152 153[note There's another form of _xform_, _xform_strict_. _xform_strict_ is 154identical to _xform_ except that it does not copy or recurse into an unmatched 155expression. Instead, a failed match is a hard error. This is useful when you 156have written a transform that you expect to completely transform an 157expression, and you want the compiler to tell you if you've made a mistake.] 158 159One common result of calling _xform_ is that you create a copy of `expr`, with 160a few matching nodes transformed. But this does not have to be the result of 161calling _xform_, because a _yap_ transformation is free-form; it must return a 162value, but may do just about anything else. It can transform an expression 163into anything _emdash_ a new expression of any kind, or even a non-expression 164value (effectively evaluating the expression). As before, here is the 165`get_arity` transform from the _calc3_ example. It returns a value, not an 166_Expr_: 167 168[calc3_get_arity_xform] 169 170Also, note that in this case the transform is stateless, but you could also 171give your transform objects data members containing contextual state: 172 173[vector_take_nth_xform] 174 175[tip Often when you create an expression, you will want to evaluate it in 176different contexts, changing its evaluation _emdash_ or even entire meaning 177_emdash_ in each context. _eval_ is wrong for this task, since it only takes 178values for substitution into placeholders. In these situations, you should 179instead use multiple transforms that evaluate your expression in different 180ways.] 181 182[heading When _xform_ Recurses] 183 184As described above, _xform_ only recurses when it *does not* find a match. 185This means that if you want to transform a nonterminal, say an 186`expr_kind::call` expression we'll call `C`, and *also* `C`'s subexpressions, 187you must explicitly call _xform_ yourself in your transform that matches `C`. 188You can see this kind of explicit _xform_ call in the recursive case of 189`get_arity` in the example code above. 190 191[note The code you write with _yap_ is likely going to be very generic, 192especially when you're writing a transform. _xform_ requires an _Expr_ as its 193first parameter. In situations when you want to make sure that the first 194parameter you pass to _xform_ is always a _yap_ expression, use the _as_expr_ 195function. This is commonly needed when writing a transform in which you 196manually recurse by calling _xform_ inside one of your transform overloads.] 197 198[heading Transform Matching] 199 200In _yap_ a _XForm_ is a _Callable_ that has *zero or more* overloads that 201model the _ExprXForm_ or _TagXForm_ concepts. 202 203An _ExprXForm_ overload takes a single parameter whose type is the expression 204to be transformed. Here's one from a transform object in the _future_group_ 205example: 206 207[expr_xform] 208 209_ExprXForms_ are most useful when you want to transform a narrow set of 210expression types (perhaps only one). In particular, you can distinguish 211between `const` and non-`const`, reference and non-reference, etc., in the 212expression and its operands in a way that you have less control over with the 213other kind of transform. 214 215A _TagXForm_ overload takes a tag that indicates the _kind_ of the expression 216to be transformed, and then (loosely) the value of each operand of the 217expression to be transformed. This looseness prevents you from needing to 218write out the full type of the matched expression. Here's one from the 219_pipable_algorithms_ example: 220 221[tag_xform] 222 223_TagXForms_ are most useful when the transform needs to match an expression 224without regard to whether its operands are _expr_ref_ expressions, or _emdash_ 225if they are terminals _emdash_ whether they contain or refer to their values. 226_TagXForms_ tend to be far more concise. 227 228[heading A More Rigorous Description of TagTransform Parameters] 229 230That "(loosely)" before probably bothered you, right? Me too. Each non-tag 231parameter is passed to a _TagXForm_ by calling an operand accessor appropriate 232to `expr`'s kind, and then calling a terminal-specific version of _value_ 233(`terminal_value()`) on the result. For example, consider a plus expression 234`expr`. The _TagXForm_ on a transform object `xform` would be called like 235this: 236 237 xform(plus_tag, terminal_value(left(expr)), terminal_value(right(expr))) 238 239The operand accessors (_left_ and _right_ in this example) all dereference 240_expr_ref_ expressions before operating on them, and `terminal_value()` does 241the same. 242 243`terminal_value()` works much like _value_, except that it does not take the 244value of a *nonterminal* unary expression; it just forwards a nonterminal 245through. It still takes values out of terminals and unwraps _expr_ref_ 246expressions, though. 247 248The auto-unwrapping of terminals means that you can effectively ignore the 249presence of _expr_ref_ expressions when writing a _TagXForm_. You can also 250just deal with the values inside terminals, and not the terminals 251themselves. Also, you can match all terminal value qualifiers (`const` or not, 252lvalue or rvalue) uniformly with a `T const &` parameter. Finally, you can 253write _TagXForm_ parameter types that can catch conversions; for instance, you 254can match any negation expression containing a terminal, *or a reference to 255one*, containing a value convertible to `double` like this: 256 257 struct xform 258 { 259 auto operator() (boost::yap::negate_tag, double x) 260 { return /* ... */; } 261 } 262 263That will match a negation of a terminal containing an `unsigned int`, 264`unsigned int &`, `int const &`, `float &&`, etc. It will also match a 265negation of a reference to such a terminal. 266 267[heading Mixing the Two Kinds of Transforms] 268 269You can have two overloads in your transform that match an expression, one an 270_ExprXForm_ and one a _TagXForm_, and there will not be any ambiguity. The 271_TagXForm_ is matched first, and the _ExprXForm_ is matched only if the 272_TagXForm_ did not. You don't have to worry about ambiguity, but save 273yourself some confusion and mix the two kinds of overloads as little as 274possible. 275 276[note The above only applies when you have an _ExprXForm_ and a _TagXForm_ 277that match *the same kind of expression*. Having unrelated _ExprXForms_ and 278_TagXForms_ within the same transform object is often quite useful.] 279 280[heading Multiple Transform Objects] 281 282In the case that multiple transform objects are being used in _xform_, the 283above logic applies to each one independently before the next one is used. In 284other words, in the call `boost::yap::transform(expr, a, b)`, _xform_ tries to 285match any _TagXForm_ from `a` to an expression first, then any _ExprXForm_ 286from `a`, then any _TagXForm_ from `b`, and finally any _ExprXForm_ from `b`. 287Only the first matching overload in this sequence is used; all overloads later 288in the sequence or in later transforms, whether they match or not, are simply 289ignored. 290 291[heading YAP-Supplied Transforms] 292 293_yap_ comes with a couple of functions that return ready-made transforms, 294_replacements_ and _evaluation_. 295 296The transforms returned by _replacements_ replace only placeholder terminals. 297Placeholder `I` is replaced by the `I-1`-th argument passed to _replacements_. 298Placeholders are `1`-based for consistency with other Boost and `std` 299placeholders. 300 301There are also a couple of specialty transform functions, 302_replace_placeholders_ and _eval_. These are convenience functions that just 303call _xform_ on an expression using _replacements_ or _evaluation_ as the 304transform, respectively. 305 306The behavior of _evaluation_ is covered in the next section, [link 307boost_yap.manual.evaluating_expressions Evaluating Expressions]. 308 309[endsect] 310 311 312[section Evaluating Expressions] 313 314_yap_ expressions are evaluated explicitly, by calling the _eval_ function or 315calling _xform_ using a transform object returned from _evaluation_. The 316former is a convenince function that does the latter. 317 318_eval_ simply removes all the _yap_ machinery from an expression and evaluates 319it exactly as it would have been if _yap_ were not used. This means that 320functions are called, operators evaluated, etc. all as normal. To illustrate 321this, take a look at the implementation of `operator,()` used in _eval_: 322 323[evaluation_transform_comma] 324 325What this transformation does is transform the left and right expressions, and 326then use the built-in `operator,()` on the result. The evaluation 327transformations for the other operators do the same thing _emdash_ evaluate 328the operands, then return the result of applying the built-in operator to the 329operands. 330 331Function calls are done in a similar way, except that the callable is also a 332subexpression that needs to be evaluated before being called: 333 334[evaluation_transform_call] 335 336[endsect] 337 338 339[section Operator Macros] 340 341If you got here without reading the _operators_ section, go read that first. 342Here are the operator macros and their uses: 343 344[table Unary and Binary Operator-Defining Macros 345 [[Macro] [Use] [First/Left Operand Type] [Right Operand Type] [Notes]] 346 347 [[_unary_m_] [Unary operators.] [An _Expr_ instantiated from _ExprTmpl_ macro parameter `expr_template`.] [--] []] 348 [[_binary_m_] [Binary operators.] [Any type.] [Any type.] [At least one parameter must be an _Expr_ instantiated from _ExprTmpl_ macro parameter `expr_template`.]] 349 [[_udt_unary_m_] [Free operators defined over non-_Expr_ types constrained by a type trait (e.g. all `std::map<>`s).] [Any non-_Expr_ that satisfies the given type trait.] [--] []] 350 [[_udt_udt_binary_m_] [Free operators defined over non-_Expr_ types constrained by a pair of type traits (e.g. a `std::map<>` on the left, and a `std::vector<>` on the right). Useful for type-asymmetric operators.] [Any non-_Expr_ that satisfies the left-hand type trait.] [Any non-_Expr_ that satisfies the right-hand type trait.] []] 351 [[_udt_any_binary_m_] [Free operators defined over pairs of non-_Expr_ types, one constrained by a type trait and one not (e.g. a `std::list<>` on either side, and anything on the other).] [Any non-_Expr_.] [--] [At least one parameter must satisfy the given type trait.]] 352] 353 354Some operators may only be defined as member functions, and so are not covered 355by general-purpose the unary and binary operator macros above: 356 357[table The Member-Only Operator Macros 358 [[Macro] [Use] [Operands] [Notes]] 359 360 [[_member_assign_m_] [Assignment operator.] [Any type except `decltype(*this)`.] [Does not conflict with the assignment or move assignment operators.]] 361 [[_member_subscript_m_] [Subscript operator.] [Any type.] []] 362 [[_member_call_m_] [Call operator taking any number of parameters.] [Any type.] []] 363 [[_member_call_n_m_] [Call operator taking exactly N parameters.] [Any type.] []] 364] 365 366[table if_else Psuedo-Operator Macros 367 [[Macro] [Use] [Operands] [Notes]] 368 369 [[_expr_if_else_m_] [Free `if_else()` function that requires at least one parameter to be an expression.] [Any type.] [At least one parameter must be an _Expr_.]] 370 [[_udt_any_if_else_m_] [Free `if_else()` function for non-_Expr_ types that requires at least one parameter to satisfy the given type trait.] [Any non-_Expr_.] [At least one parameter must satisfy the given type trait.]] 371] 372 373[note Operands are handled in a uniform way across all functions defined by 374all the macros listed here. See _how_treated_ for details.] 375 376[endsect] 377 378 379[section How Expression Operands Are Treated] 380 381For any _expr_ operator overload, or any function defined using one of the 382function definition macros, operands are treated in a uniform way. 383 384The guiding design principle here is that an expression built using _yap_ 385should match the semantics of a builtin C++ expression as closely as possible. 386This implies that an rvalue be treated as if it were a temporary (as it may in 387fact have initially been) throughout the building and transformation of an 388expression, and that an lvalue should retain its connection to the underlying 389named entity to which it refers. 390 391For example, if you see 392 393 auto expr = a + 1; 394 395you should expect that `a` will be an lvalue reference to some object of type 396`decltype(a)`, regardless of whether `a` is a _yap_ _Expr_ or a builtin type. 397Similarly, you should expect the `1` to be an rvalue, whether wrapped in a 398terminal or not. 399 400Let's take a quick look at _make_term_. If you call it with a `T` rvalue, the 401terminal's value type is a `T`, and the rvalue gets moved into it. If you 402call it with a `T [const]` lvalue, the value type is `T [const] &`, and the 403reference refers to the lvalue (read `[const]` as "possibly 404`const`-qualified"). This is important because you might write through the 405terminal later in an assignment operation. You don't want to lose the ability 406to do this, or be forced to write some Baroque pile of code to do so _emdash_ 407it should be natural and easy. 408 409And it is: 410 411[assign_through_terminal] 412 413Now, there is a wrinkle. _yap_'s lazy expressions can be built piecemeal: 414 415 auto subexpr = boost::yap::make_terminal(1) + 2; 416 // This is fine, and acts more-or-less as if you wrote "1 / (1 + 2)". 417 auto expr = 1 / subexpr; 418 419whereas C++'s eager builtin expressions cannot: 420 421 auto subexpr = 1 + 2; // Same as "int subexpr = 3;". Hm. 422 auto expr = 1 / subexpr; // Same as "int expr = 0;" Arg. 423 424Ok, so since you can build these lazy _yap_ expressions up from 425subexpressions, how do we treat the subexpressions? We treat them in exactly 426the same way as _make_term_ treats its parameter. Rvalues are moved in, and 427lvalues are captured by (possibly `const`) reference. 428 429[note If you want to subvert the capture-by-reference semantics of using 430subexpressions, just `std::move()` them. That will force a move _emdash_ or 431copy of values for which move is not defined.] 432 433The capture-by-reference behavior is implemented via a special _kind_, 434_expr_ref_. An `expr_ref` expression has a single data element: a (possibly 435`const` (Can I stop saying that every time? You get it, right? Ok, good.)) 436reference to an expression. This additional level of indirection causes some 437complications at times, as you can see in the examples. Fortunately, the 438complications are not overly cumbersome. 439 440So, given the rules above, here is a comprehensive breakdown of what happens 441when an operand is passed to a _yap_ operator. In this table, `expr_tmpl` is 442an _ExprTmpl_, and `T` is a non-_Expr_ type. `E` refers to any non-`expr_ref` 443_Expr_. _yap_ does a partial decay on non-_Expr_ operands, in which `cv` and 444reference qualifiers are left unchanged, but arrays are decayed to pointers 445and functions are decayed to function pointers. `PARTIAL_DECAY(T)` indicates 446such a partial decay of `T`. 447 448[table Operand Handling 449 [[Operand] [Captured As] [Notes]] 450 451 [[`T const &`] [`expr_tmpl<expr_kind::terminal, boost::hana::tuple<PARTIAL_DECAY(T)>>`] []] 452 [[`T &`] [`expr_tmpl<expr_kind::terminal, boost::hana::tuple<PARTIAL_DECAY(T)>>`] []] 453 [[`T &&`] [`expr_tmpl<expr_kind::terminal, boost::hana::tuple<PARTIAL_DECAY(T)>>`] [Operand moved.]] 454 455 [[`E const &`] [`expr_tmpl<expr_kind::expr_ref, boost::hana::tuple<E const &>>`] []] 456 [[`E &`] [`expr_tmpl<expr_kind::expr_ref, boost::hana::tuple<E &>>`] []] 457 [[`E &&`] [`E`] [Operand moved.]] 458 459 [[`expr_tmpl<expr_kind::expr_ref, ...> const &`] [`expr_tmpl<expr_kind::expr_ref, ...>`] []] 460 [[`expr_tmpl<expr_kind::expr_ref, ...> &`] [`expr_tmpl<expr_kind::expr_ref, ...>`] []] 461 [[`expr_tmpl<expr_kind::expr_ref, ...> &&`] [`expr_tmpl<expr_kind::expr_ref, ...>`] [Operand moved.]] 462] 463 464The partial decay of non-_Expr_ operands is another example of how _yap_ 465attempts to create expression trees that are as semantically close to builtin 466expressions as possible. 467 468[endsect] 469 470 471[section Printing] 472 473_yap_ has a convenient _print_ function, that prints an expression tree to a 474stream. It is not intended for production work (for instance, it has no 475formatting options), but it is excellent for debugging and instrumentation. 476 477Since it is only a debugging aid, _print_ is found in a separate header not 478included when you include _yap_ with 479 480 #include <boost/yap/yap.hpp> 481 482You must include `<boost/yap/print.hpp>` explicitly. 483 484_print_ handles several patterns of expression specially, to allow a concise 485representation of a given expression tree. For example, given this 486definition: 487 488[print_decl] 489 490and this expression: 491 492[print_expr] 493 494_print_ produces this output: 495 496[pre 497expr<-> 498 expr<+> 499 term<boost::yap::placeholder<4ll>>[=4\] 500 expr<*> 501 term<double &>[=1\] 502 term<thing>[=<<unprintable-value>>\] & 503 term<char const*>[=lvalue terminal\] const & 504] 505 506As you can see, _print_ shows one node per line, and represents the tree 507structure with indentation. It abbreviates non-terminal nodes in the tree 508`expr<op>`, where `op` is an operator symbol. Terminal nodes are abbreviated 509`term<T>`, where `T` is the type of value contained in the terminal; this may 510be a reference type or a value. 511 512A `term` node may not be a terminal node at all, but an _expr_ref_ expression 513containing a terminal. Such a _expr_ref_ node has a `&` or `const &` suffix, 514to indicate that it is a mutable or `const` reference, respectively. 515 516Each `term` node has a bracketed value near the end. The format is `[=X]` 517where `X` is the value the terminal contains. If the terminal contains a 518value for which no `operator<<(std::ostream &, ...)` overload exists (such as 519the `thing` type above), `X` will be `<<unprintable-value>>`. 520 521[endsect] 522