]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | [/============================================================================== |
2 | Copyright (C) 2001-2011 Joel de Guzman | |
3 | Copyright (C) 2006 Dan Marsden | |
4 | ||
5 | Use, modification and distribution is subject to the Boost Software | |
6 | License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at | |
7 | http://www.boost.org/LICENSE_1_0.txt) | |
8 | ===============================================================================/] | |
9 | [section Introduction] | |
10 | ||
11 | An advantage other languages such as Python and Lisp/ Scheme, ML and | |
12 | Haskell, etc., over C++ is the ability to have heterogeneous containers | |
13 | that can hold arbitrary element types. All the containers in the standard | |
14 | library can only hold a specific type. A `vector<int>` can only hold | |
15 | `int`s. A `list<X>` can only hold elements of type `X`, and so on. | |
16 | ||
17 | True, you can use inheritance to make the containers hold different types, | |
18 | related through subclassing. However, you have to hold the objects through | |
19 | a pointer or smart reference of some sort. Doing this, you'll have to rely | |
20 | on virtual functions to provide polymorphic behavior since the actual type | |
21 | is erased as soon as you store a pointer to a derived class to a pointer to | |
22 | its base. The held objects must be related: you cannot hold objects of | |
23 | unrelated types such as `char`, `int`, `class X`, `float`, etc. Oh sure you | |
24 | can use something like __boost_any__ to hold arbitrary types, but then you | |
25 | pay more in terms of runtime costs and due to the fact that you practically | |
26 | erased all type information, you'll have to perform dangerous casts to get | |
27 | back the original type. | |
28 | ||
29 | The __tuple__ library written by __jaakko_jarvi__ provides heterogeneous | |
30 | containers in C++. The `tuple` is a basic data structure that can hold | |
31 | heterogeneous types. It's a good first step, but it's not complete. What's | |
32 | missing are the algorithms. It's nice that we can store and retrieve data | |
33 | to and from tuples, pass them around as arguments and return types. As it | |
34 | is, the __tuple__ facility is already very useful. Yet, as soon as you use | |
35 | it more often, usage patterns emerge. Eventually, you collect these | |
36 | patterns into algorithm libraries. | |
37 | ||
38 | Hmmm, kinda reminds us of STL right? Right! Can you imagine how it would be | |
39 | like if you used STL without the algorithms? Everyone will have to reinvent | |
40 | their own /algorithm/ wheels. | |
41 | ||
42 | Fusion is a library and a framework similar to both __stl__ and the boost | |
43 | __mpl__. The structure is modeled after __mpl__, which is modeled | |
44 | after __stl__. It is named "fusion" because the library is reminiscent of | |
45 | the "fusion" of compile time meta-programming with runtime programming. The | |
46 | library inherently has some interesting flavors and characteristics of both | |
47 | __mpl__ and __stl__. It lives in the twilight zone between compile time | |
48 | meta-programming and run time programming. __stl__ containers work on | |
49 | values. MPL containers work on types. Fusion containers work on both types | |
50 | and values. | |
51 | ||
52 | Unlike __mpl__, Fusion algorithms are lazy and non sequence-type | |
53 | preserving. What does that mean? It means that when you operate on a | |
54 | sequence through a Fusion algorithm that returns a sequence, the sequence | |
55 | returned may not be of the same class as the original. This is by design. | |
56 | Runtime efficiency is given a high priority. Like __mpl__, and unlike | |
57 | __stl__, fusion algorithms are functional in nature such that algorithms | |
58 | are non mutating (no side effects). However, due to the high cost of | |
59 | returning full sequences such as vectors and lists, /Views/ are returned | |
60 | from Fusion algorithms instead. For example, the __transform__ algorithm | |
61 | does not actually return a transformed version of the original sequence. | |
62 | __transform__ returns a __transform_view__. This view holds a reference to | |
63 | the original sequence plus the transform function. Iteration over the | |
64 | __transform_view__ will apply the transform function over the sequence | |
65 | elements on demand. This /lazy/ evaluation scheme allows us to chain as | |
66 | many algorithms as we want without incurring a high runtime penalty. | |
67 | ||
68 | The /lazy/ evaluation scheme where algorithms return views allows | |
69 | operations such as __push_back__ to be totally generic. In Fusion, | |
70 | __push_back__ is actually a generic algorithm that works on all sequences. | |
71 | Given an input sequence `s` and a value `x`, Fusion's __push_back__ | |
72 | algorithm simply returns a __joint_view__: a view that holds a reference to | |
73 | the original sequence `s` and the value `x`. Functions that were once | |
74 | sequence specific and need to be implemented N times over N different | |
75 | sequences are now implemented only once. | |
76 | ||
77 | Fusion provides full round compatibility with __mpl__. Fusion sequences are | |
78 | fully conforming __mpl__ sequences and __mpl__ sequences are fully compatible | |
79 | with Fusion. You can work with Fusion sequences on __mpl__ if you wish to work | |
80 | solely on types [footnote Choose __mpl__ over fusion when doing pure type | |
81 | calculations. Once the static type calculation is finished, you can instantiate | |
82 | a fusion sequence (see __conversion__) for the runtime part.]. In __mpl__, | |
83 | Fusion sequences follow __mpl__'s sequence-type preserving semantics (i.e. | |
84 | algorithms preserve the original sequence type. e.g. transforming a vector | |
85 | returns a vector). You can also convert from an __mpl__ sequence to a Fusion | |
86 | sequence. For example, there are times when it is convenient to work solely on | |
87 | __mpl__ using pure __mpl__ sequences, then, convert them to Fusion sequences as | |
88 | a final step before actual instantiation of real runtime objects with data. You | |
89 | have the best of both worlds. | |
90 | ||
91 | [endsect] |