Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 203 lines (154 sloc) 6.635 kb
27494a2 @jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored
1 `folly/dynamic.h`
2 -----------------
3
4 `folly/dynamic.h` provides a runtime dynamically typed value for
5 C++, similar to the way languages with runtime type systems work
6 (e.g. Python). It can hold types from a predetermined set of types
7 (ints, bools, arrays of other dynamics, etc), similar to something like
8 `boost::variant`, but the syntax is intended to be a little more like
9 using the native type directly.
10
11 To use `dynamic`, you need to be using gcc 4.6 or later. You'll want to
12 include `folly/dynamic.h` (or perhaps also `folly/json.h`).
13
14 ### Overview
15 ***
16
17 Here are some code samples to get started (assumes a `using
18 folly::dynamic;` was used):
19
20 ``` Cpp
21 dynamic twelve = 12; // creates a dynamic that holds an integer
22 dynamic str = "string"; // yep, this one is an fbstring
23
24 // A few other types.
25 dynamic nul = nullptr;
26 dynamic boolean = false;
27
28 // Arrays can be initialized with brackets.
29 dynamic array = { "array ", "of ", 4, " elements" };
30 assert(array.size() == 4);
31 dynamic emptyArray = {};
32 assert(array.empty());
33
34 // Maps from dynamics to dynamics are called objects. The
35 // dynamic::object constant is how you make an empty map from dynamics
36 // to dynamics.
37 dynamic map = dynamic::object;
38 map["something"] = 12;
39 map["another_something"] = map["something"] * 2;
40
41 // Dynamic objects may be intialized this way
42 dynamic map2 = dynamic::object("something", 12)("another_something", 24);
43 ```
44
45 ### Runtime Type Checking and Conversions
46 ***
47
48 Any operation on a dynamic requires checking at runtime that the
49 type is compatible with the operation. If it isn't, you'll get a
50 `folly::TypeError`. Other exceptions can also be thrown if
51 you try to do something impossible (e.g. if you put a very large
52 64-bit integer in and try to read it out as a double).
53
54 More examples should hopefully clarify this:
55
56 ``` Cpp
57 dynamic dint = 42;
58
59 dynamic str = "foo";
60 dynamic anotherStr = str + "something"; // fine
61 dynamic thisThrows = str + dint; // TypeError is raised
62 ```
63
64 Explicit type conversions can be requested for some of the basic types:
65
66 ``` Cpp
67 dynamic dint = 12345678;
68 dynamic doub = dint.asDouble(); // doub will hold 12345678.0
69 dynamic str = dint.asString(); // str == "12345678"
70
71 dynamic hugeInt = std::numeric_limits<int64_t>::max();
72 dynamic hugeDoub = hugeInt.asDouble(); // throws a folly/Conv.h error,
73 // since it can't fit in a double
74 ```
75
5b67454 Added dynamic::convertTo<Type> method
Nicholas Ormrod authored
76 For more complicated conversions, see [DynamicConverter](DynamicConverter.md).
77
27494a2 @jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored
78 ### Iteration and Lookup
79 ***
80
81 You can iterate over dynamic arrays as you would over any C++ sequence container.
82
83 ``` Cpp
84 dynamic array = {2, 3, "foo"};
85
86 for (auto& val : array) {
87 doSomethingWith(val);
88 }
89 ```
90
91 You can iterate over dynamic maps by calling `items()`, `keys()`,
92 `values()`, which behave similarly to the homonymous methods of Python
93 dictionaries.
94
95 ``` Cpp
96 dynamic obj = dynamic::object(2, 3)("hello", "world")("x", 4);
97
98 for (auto& pair : obj.items()) {
99 // Key is pair.first, value is pair.second
100 processKey(pair.first);
101 processValue(pair.second);
102 }
103
104 for (auto& key : obj.keys()) {
105 processKey(key);
106 }
107
108 for (auto& value : obj.values()) {
109 processValue(value);
110 }
111 ```
112
113 You can find an element by key in a dynamic map using the `find()` method,
114 which returns an iterator compatible with `items()`:
115
116 ``` Cpp
117 dynamic obj = dynamic::object(2, 3)("hello", "world")("x", 4);
118
119 auto pos = obj.find("hello");
120 // pos->first is "hello"
121 // pos->second is "world"
122
123 auto pos = obj.find("no_such_key);
124 // pos == obj.items().end()
125 ```
126
127
128 ### Use for JSON
129 ***
130
131 The original motivation for implementing this type was to try to
132 make dealing with json documents in C++ almost as easy as it is
133 in languages with dynamic type systems (php or javascript, etc).
134 The reader can judge whether we're anywhere near that goal, but
135 here's what it looks like:
136
137 ``` Cpp
138 // Parsing JSON strings and using them.
139 std::string jsonDocument = R"({"key":12,"key2":[false, null, true, "yay"]})";
140 dynamic parsed = folly::parseJson(jsonDocument);
141 assert(parsed["key"] == 12);
142 assert(parsed["key2"][0] == false);
143 assert(parsed["key2"][1] == nullptr);
144
145 // Building the same document programatically.
146 dynamic sonOfAJ = dynamic::object
147 ("key", 12)
148 ("key2", { false, nullptr, true, "yay" });
149
150 // Printing. (See also folly::toPrettyJson)
151 auto str = folly::toJson(sonOfAJ);
152 assert(jsonDocument.compare(str) == 0);
153 ```
154
155 ### Performance
156 ***
157
158 Dynamic typing is more expensive than static typing, even when
159 you do it in C++. ;)
160
161 However, some effort has been made to keep `folly::dynamic` and
162 the json (de)serialization at least reasonably performant for
163 common cases. The heap is only used for arrays and objects, and
164 move construction is fully supported. String formatting
165 internally also uses the highly performant `folly::to<>` (see
166 `folly/Conv.h`).
167
168 A trade off to keep in mind though, is that
169 `sizeof(folly::dynamic)` is 64 bytes. You probably don't want to
170 use it if you need to allocate large numbers of them (prefer
171 static types, etc).
172
173 ### Some Design Rationale
174 ***
175
176 **Q. Why is there no default constructor?**
177
178 This is a bit of a limitation of `std::initializer_list<>` for
179 this use case. The expression `dynamic d = {}` is required by the
180 standard to call the default constructor if one exists (the
181 reasoning for this makes sense, since `{}` is part of the concept
182 of "uniform initialization", and is intended for use with things
183 like `std::vector`). It would be surprising if this expression
184 didn't leave `d.isArray()` true, but on the other hand it would
185 also be surprising if `dynamic d` left `d.isArray()` as true. The
186 solution was just to disallow uninitialized dynamics: every
187 dynamic must start out being assigned to some value (or nullptr).
188
e825366 @jdelong Add a FAQ item about dynamic strings
jdelong authored
189 **Q. Why doesn't a dynamic string support begin(), end(), and operator[]?**
190
191 The value_type of a dynamic iterator is `dynamic`, and `operator[]`
192 (or the `at()` function) has to return a reference to a dynamic. If
193 we wanted this to work for strings, this would mean we'd have to
194 support dynamics with a character type, and moreover that the internal
195 representation of strings would be such that we can hand out
196 references to dynamic as accessors on individual characters. There
197 are a lot of potential efficiency drawbacks with this, and it seems
198 like a feature that is not needed too often in practice.
199
27494a2 @jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored
200 **Q. Isn't this just a poor imitation of the C# language feature?**
201
202 Pretty much.
Something went wrong with that request. Please try again.