When the solution came, it wasn't where we had expected it.
We had been concentrating on the alien artifacts left strewn about the alien city buried out here under the European ice. So much of our time had been spent in here, underground, and I missed not being able to take off-duty time out on the surface and take in the silent majesty of King Jupiter filling the sky. But the surface was not safe, not now, with occupying forces on their way.
Using Jäger's new information about the alien language, we had just managed to activate several of the devices, although so far we couldn't tell what they did. We knew we should be careful, but we hadn't the luxury of time for that. The whole purpose, I realized, was for our leaders' faction to gain control of the alien technology, especially if it had military applications. The opposing faction was taking a rather dim view, and I wondered if we hadn't been overrun by them already. It couldn't be long now, days or hours.
But the solution wasn't in the artifacts. It was in the Ballroom.
The dark, icebound city was full of unexplored chambers and chasms, hallways and dead ends. Of the ones we'd found, the most intriguing was the Ballroom our name for an immense room empty but for three 10-foot-diameter metallic balls fixed suspended in midair. How they were suspended, we had no idea, but it was when we found some of the city's power controls that they came alive.
I was there when it happened. "What the" started one of the techs with us, but then he stopped. That was all any of us could say just then.
Each of the balls showed a different scene. In one, we could see a brightly lit field of yellowish grasses with what looked like trees in the near distance. In another ball was a beach scene at dusk. The third showed a metallic room much like those here in the buildings, filled with rows of chest-high cabinets.
We stared, and when nothing else happened immediately, we began to move around the balls. The scenes shifted, as though we were really walking around and looking through each ball like a hole into another place, but behind the ball our original room still stood as solid as ever.
"What's in those balls? Are those pictures, or... or where are those places?" Jeannine said, hushed, when she found her voice. A tech, brought out of his wonder by the words, remembered to hurry off to call our ranking officer, who undoubtedly would call Major Gilb.
"I don't know," I said slowly, awed but curious. "They could hold anything. And they could lead anywhere..."
It was rather quiet around work. Many of the staff had left early for the holidays. I, on the other hand, had not been around long enough to accrue much vacation time, so I had to work right up to the holiday shutdown. Of course, this made it much more difficult to get help when I started running into brick walls, like the one I was facing now.
I needed to have a variable that could hold any type of data. My first instinct was to use a template after all, they're great for generic programming:
template <typename ValueType> class multiType { ValueType value_; public: multiType(const ValueType &t) : value_(t) {} operator ValueType() { return value_; } };
Unfortunately, I quickly ran into the first wall there were places in the code where one variable might have to hold different types of information during its lifetime, like this:
{ multiType<const char *> multiA("Hello, World"); // ... some code ... multiType<long> multiB(99L); // ... some more code ... multiA = multiB; // Oops -- can't convert from long to const char *. }
At this point, I needed multiA
to forget that it started life as a multiType<const char *>
and start acting like it was a multiType<long>
. It started to look like I had two choices a union
or a void
pointer. I knew enough of the dangers of void
pointers, so I decided to use a union
:
class multiType { enum ValueType { Long, ConstCharPtr }; union { const char * c_; long l_; } value_; ValueType currentType_; public: multiType(const char * c); multiType & operator =(const char * c); operator const char *(); multiType(long); multiType & operator =(long); operator long(); };
By wrapping the union
in a class, I had achieved some degree of encapsulation. At least the conversion operators could check that the value type being held was appropriate. I wasn't looking forward to the copy-and-paste exercise ahead of me, to implement all the overloaded constructors and conversion operators that would eventually be needed. (long
and const char *
were only the tip of the iceberg.)
"You need any
."
I jumped at the Guru's voice almost as much as I used to when I was still an intern. Even with the office as quiet as it was, I had still failed to hear her approach. "Uh," I stammered, "do I need any what?"
"No, my child," she smiled, shutting the large tome in her hand, "that was not a question; that was a statement. You need any
."
"Oookay," I replied. I toyed with the idea of using my deer-in-the-headlights look, but decided to go for the direct approach instead and asked: "Ah, would you mind elaborating slightly?"
"A thousand pardons, my apprentice," the Guru bowed. I began wondering why she was in her full Guru act with the office as empty as it was then I saw Bob heading towards the kitchen for a fresh latte. I knew that the full Guru shtick was used mainly for two reasons: to scare fresh, young recruits, and to annoy the bejeepers out of Bob. "I keep forgetting that you are barely a novitiate," she continued, "and not yet fully trained in the ways of the Programmer." I bristled slightly at that but then I realized she was right. The more I learned, the less I knew, it seemed.
"I am referring to the Boost library's any
class," the Guru continued.
"What's the Boost library? I haven't heard of it."
She smiled a smile of mild surprise. "Indeed? You should. The Boost library is a collection of C++ source libraries. Boost was founded by some of the blessed disciples on the C++ Standards Committee."
"Oh, so it's related to the Standard?"
"Not directly," the Guru replied. "The founding members of Boost are not-so-coincidentally members of the C++ Standards Committee, but otherwise Boost has no official connection with ISO or any other standards body. The blessed writings available at the Boost website, <www.boost.org>, are intended to be candidates for proposal as new standard library items in the next revision of the Holy Standard, but of course there is no guarantee that they will be accepted by the Committee."
"Ah," I ahhed, as I digested that. "So what is this any
class you mentioned?"
"The any
class, simply put, allows a variable to hold any type of value. An any
could hold anything. For example," she picked up the marker and began writing on my whiteboard:
#include <iostream> #include <boost/any.hpp> const char * initialMessage = "Snowflakes keep falling on my head"; int main() { boost::any multiA(42L); boost::any multiB(initialMessage); multiA = multiB; std::cout << boost::any_cast<const char *>(multiA) << std::endl; }
"In this parable, multiA
begins life holding a long.
The assignment from multiB
essentially converts multiA
into a const char *
. The output of the program, therefore, will be 'Snowflakes keep falling on my head'," the Guru concluded as she put down the marker.
"That's cool. What's that any_cast
do? I didn't know any_cast
was a C++ keyword, but it must be a keyword because it isn't qualified by boost::
...?"
"No, it is a free function template. It makes its home in the boost
namespace, but because the object we pass it is also from namespace boost
, compilers that correctly implement Koenig lookup alas, not all do will find the function correctly even without a using-declaration or explicit qualification. The any_cast
is intended to be analogous to the already-blessed dynamic_cast
. It will attempt to convert the given operand into the type requested. If the conversion is possible, the cast returns the original object converted to the desired type. If not, then the cast returns a null
pointer if the operand was a pointer or throws an exception if the operand was a reference or object."
I was impressed. "Well, it looks easy enough to copy any
objects and extract the values, but in that code you knew the value you wanted the any
object to hold at the time you created it. What if you don't know the value until later? Do you have to construct another any
helper and then assign from it like that?"
"No, my child." In the near distance, I noticed Bob's head appear partially around a cubicle divider, shake disgustedly at these words, and disappear again. The Guru smiled enigmatically. "The any
class provides a templated assignment operator, allowing you to easily write code such as:"
{ boost::any holdsAnything; holdsAnything = 9; holdsAnything = std::string("Hello, world"); holdsAnything = 3.1415926; }
"You will also note," the Guru continued, "that the any
class supports null or empty semantics, which is to say, the value type currently holds no value. Further, to facilitate extracting the value, the any
class provides a type
function, which returns a std::type_info
class, indicating the type of value currently held in the any
class."
"Say," I barged in. "I just thought of something this would be a great way to implement properties. Just create a struct
that has a std::string
for the property name, and an any
class for the property value."
"Indeed, my young apprentice," the Guru nodded. "The prophet Henney suggests properties as one potential use of any
[2]. For an any
could hold anything. And it could lead anywhere..."
"What? How do you mean?"
"Because," she explained, "another possibility is to use an any
class as the parameter for polymorphic-based callbacks. As I recall, the example Henney gives is:"
class consumer { public: virtual void notify(const any &) = 0; };
"Ah. Well, anyway," I grinned, "thanks for providing me the piece of the puzzle I needed." The Guru bowed her head, reopened her tome, and glided silently away as I turned back to my keyboard.
"Excellent work, excellent, most excellent," Gilb kept repeating. "Unusual, most unusual. What about the artifacts? Has there been more progress? Have we found anything new to defend ourselves?"
That irked me. "Major," I blurted, "we have no idea what this is or what it means. I know our situation, but there's much more to this than weapons! We've already performed one test and "
"You forget yourself," the major cut me off. It was the first time he had done that, and I stopped. Then, resuming his usual cajoling voice, he continued: "We're all under stress. We haven't much time, no time at all. This test, what was it, what did you do?"
"A pole," Jeannine responded. "We took a long pole and put it against the ball. It entered, without resistance, and we could see it leave a mark on the beach. We pushed the pole in further than the ball is wide, and it didn't come out the other side of the ball here. It's still there," she gestured and moved to show him, and we shifted to follow her. "It's as if that beach was right there, within arm's reach. I haven't tried, but I'm sure I could touch it. The ball is like a hole in the universe."
Gilb took in this information, then moved to the grassy scene, and then to the metallic room scene.
Just then, as we circled the metallic room to look out at it from different directions, something new came into view. A man dressed in an oddly cut gray costume was standing at one of the cabinets, holding some sort of flat device and manipulating it. Suddenly, as though just aware of us, he turned in our direction and stared. His mouth began moving, and after the briefest pause we heard in English: "Should you be here?"
References
[1] To the tune of "I'd Do Anything," Oliver!, 1968.
[2] C++ Boost any
class, Kevlin Henney, <www.boost.org/libs/any/index.html>.
Jim Hyslop is a senior software designer at Leitch Technology International Inc. He can be reached at [email protected].
Herb Sutter is an independent consultant and secretary of the ISO/ANSI C++ standards committee. He is also one of the instructors of The C++ Seminar (<www.gotw.ca/cpp_seminar>). Herb can be reached at [email protected].