Boost logo

Boost :

From: Corwin Joy (cjoy_at_[hidden])
Date: 2001-07-15 13:26:43


--- In boost_at_y..., "Peter Dimov" <pdimov_at_m...> wrote:
> From: "Corwin Joy" <cjoy_at_h...>
> [...]
> > Sure. The point is to have a seperate class from the basic "any" class
> since
> > it provides extra facilities but also places additional requirements on
> the
> > held object - e.g. that it be streamable.
> [...]
> > This does not at all defeat the purpose of supporting I/O. There any
many
> > times when you want to use "any" as a kind of prototype design where
where
> > you say that the type must is set by the initial construction and any
> > further "writes" to that type must be cast into that type.
>
> Could you please provide an example of such a design? This is quite
> interesting.

Sure. We have a variant class in the Database Template Library that I
co-authored (http://www.geocities.com/corwinjoy/dtl/index.htm). What
happens is that at construction time, the program analyzes the table being
bound to and determines the types of the columns such as date, string,
integer, wide-string etc. Once these types have been determined a variant
is constructed to hold each database column. After initial construction,
any writes into this variant class are not allowed to change the variant's
type (otherwise the database binding would become invalid). So, writes into
the variant are cast into whatever type is currently held by the object. If
the cast cannot be performed, a runtime exception is thrown.
I think other examples of this "type" prototype are out there. Examples
might be initial parsing of a file to determine the types of fields held and
then holding this types fixed after construction or other applications where
the metadata is analyzed seperately from the value and needs to remain fixed
after construction.

>
> FWIW, here's how I think the 'any' evolution should proceed:
>
> Do not introduce separate concepts that add features. The reason is that
an
> important purpose of 'any' is to define 'typeless' interfaces, like
variadic
> functions:
>
> void call_script_function(std::string name, std::vector<any> args);
>
> Having an 'anyx' would lead to the common problem where you pass your anyx
> to a library function (converting it to any), then that library hands you
an
> 'any' back and you need a dynamic_cast-related facility to determine
whether
> this 'any' is an 'anyx' or not.
>
O.K. I guess I can see this. My concern was not to burden any with
additional requirements on the held type - but it sounds like you have some
nice ideas in this direction.

> What I envision is this:
>
> * support stream I/O:
>
> #include <boost/any/iostream.hpp>
>
> register_stream_inserter<int>();
> register_stream_inserter<double>();
> register_stream_inserter<std::string>();
>
> register_stream_extractor<int>(/* regex */ "[\\+\\-]?[0-9]+", /* priority
*/
> 10);
> register_stream_extractor<double>("[\\+\\-]?[0-9]+(\\.[0-9]*)?", 10);
> register_stream_extractor<std::string>("[^ \r\n\t]+", 0);
>
> // longest match wins, priority used to break ties

This sounds interesting - I'm not quite sure how the register methodology
works with the held value type. I'd be interested to see how you integrate
the register templates shown above with the virtual mechanism required by
the holder class for any. Also, one other minor point, I think your
extractors above would need some kind of notion of a terminating token(s) so
that string does not always win.

>
> boost::any a;
>
> while(std::cin >> a) // extraction fails on no match
> {
> std::cout << a; // throws std::logic_error on no match
> }
>
> * support conversions:
>
> #include <boost/any/conversions.hpp>
>
> register_conversion<int, double>(rank_implicit);
> register_conversion<double, int>(rank_diagnostic);
> register_conversion<int, std::string>(rank_explicit,
> my_conversion_int_string);
>
> any a(1.0);
>
> convert_to<int>(a); // returns 1, type int
> convert_to<std::string>(a); // fails (std::bad_cast)
>

This kind of thing would be really cool. Here I *really* can't see how this
would work with the virtual function mechanism required by any. How exactly
would you modify the placeholder class to do this. (Or were you planning on
a massive switch...case base on the type_info (shudder...) :-O ).

> * support operators:
>
> #include <boost/any/operators.hpp>
>
> register_operator_plus<int>();
> register_operator_plus<double>();
> register_operator_plus<std::string>();
>
> any a(1), b(1.4);
>
> a + b; // returns any(2.4) since int->double ranks better than double->int
>

I like the idea of extending any to support operators. For complexity
reasons in my mind there are two cases:
Case 1:
Operators on homogenous types e.g.:
double + double
int + int
complex + complex
... these are not too hard to support within the current "any" framework.

Case 2:
Operations of hetrogeneous types e.g.:
int + double
int + long
complex + int (?)

Probably this does imply promotion rules ... which can be made not too hard
if you already have the cast operations you describe above. (Again, I am
having diffuculties seeing how to make these casts work with the virtual
mechanism as I noted above. This is why I have split this out a seperate
case since I feel the complexity is much higher.).

> any("this") + any(" or that"); // returns any("this or that")
>
> a += any("string"); // fails with std::logic_error, explicit conversions
not
> considered
>
> Now we are very close to a simple but full-featured scripting language.
:-)
>
> What do you think? [The above can be implemented with no changes to
> boost::any, I believe.]
>

This would be awesome if it were possible. In practice I fear that the
language constraints might make it hard to get here.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk