$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
From: Jonathan Turkanis (technews_at_[hidden])
Date: 2005-01-30 14:28:39
christopher diggins wrote:
> ----- Original Message -----
> From: "Jonathan Turkanis" <technews_at_[hidden]>
>> Cloning must be introduced at some point. I've been trying to find a
>> way to make cloning just another function, but am becoming convinced it's sui
>> generis. Since Thortsen uses cloning for his Smart Containers library, I
think I'll
>> just borrow concepts and machinery from him.
>>
>> I'm not sure what you mean by "clone(interface_value)", though.
>
> I meant Clone() should be a global function instead of a member
> function to avoid namespace clashes.
You mean it should be defined in the global namespace? Defining stuff in the
global namespace *causes* clashes.
> I am not sure I understand what you mean by making cloning as just
> another function.
I'm not sure what I mean either. I guess I was hoping that a natural and elegant
treatment of cloning would appear magically. :-)
> I also don't think Clone is unique. Clone is
> essentially a call to the copy constructor of the object,
This doesn't work for polymorphic classes. For instance, you might be given an
object as a pointer or reference to an abstract class. More generally, you
typically want to call the copy constructor of the *most-derived* class, but you
may be given a pointer or reference to a base class. And you might want to call
a member function clone() even if the static type has an accessible copy
constructor.
As a result, a more general treatment, like Thorsten's, is needed.
The same problem exists for destructors, but there is a built-in language
mechanism to solve the problem: the virtual destructor. So we adopt the
convention that an object of a class without a virtual destructor should never
be passed around as a pointer to a base class.
> So I would propose (renaming Clone to new_copy):
I prefer clone(), since it is an established name.
> AnyInterface i = AnyObject;
> //...
> if (has_copy_ctor(i) && has_dtor(i)) {
> manual_ptr<AnyInterface> p = new_copy(i);
> }
The problem here is that there's no portable way to tell whether a type has an
accessible destructor or copy constructor. With the smart pointer templates, the
burden is on the user: you can't bind a dynamically allocated object to a smart
pointer unless the static type of the object has an accessible destructor or or
unless you're using shared_ptr with a custom deleter.
Similarly, we need a way to put the burden on the user for clonability. Daniel
James suggested having a special clone function which could be declared in an
interface:
BOOST_IDL_BEGIN(IBar)
BOOST_IDL_CLONE()
...
BOOST_IDL_END(IBar)
> also:
>
> AnyInterface i = AnyObject;
> //...
> if (has_default_ctor(i) && has_dtor(i)) {
> manual_ptr<AnyInterface> p = new_default_ctor(i);
> }
Here, again, unless you know how to determine whether an object has a trivial
default constructor, we'd have to put the burden on the user. E.g.,
BOOST_IDL_BEGIN(IBar)
BOOST_IDL_DEFAULT_CTOR()
...
BOOST_IDL_END(IBar)
This case doesn't seem as useful as clone, IMO.
Also, it's important to note that adding more than a tightly controlled handful
of functions to interface tables can lead to code bloat, even when these
functions are not used.
> Both pieces of code above are extremely useful, especially if we want
> interfaces to have the same expressive power as boost::any.
I don't think Boost.Any ever assumes that user defined types are default
constructible.
> I am
> currently redesigning my Object class in the OOTL, and if I have the
> two above functions, it means that my objects no longer need any
> special macros. (Remember OOTL_DEF_OBJECT?).
Okay, I'm open to suggestions on how to implement this.
>> You could determine this stuff (to the extent the language allows)
>> at the time of binding, and make it available at runtime.
>
> Do you mean by adding functions to the class?
I meant you could determine the results of a bunch of boolean traits, and store
them as flags in the interface table. However, I didn't understand why you
wanted this information.
> I want to automate the
> process somewhat and remove my dependence on my stupid
> DEF_OOTL_OBJECT macro. If you don't provide this functionality within
> interface,
I'll certainly implement cloning, one way or another. I'm not yet convinced of
the value of default construction, though.
> then I would like to know how to create new interface
> types which do that. I would like to be able to create a new
> interface types, which interject new functions into the function tables.
> I think this ability (to inherit from interface types and interject new
> functions into function tables) should be part of the interface functionality.
There are two problems:
- it's hard to see how to allow users to customize the interface infrastructure,
since it's macro-based. There's just no place to stick policies
- some of this functionality can only be made available for a subset of the
classes whose instances a user might want to bind to an interface. Different
user actions trigger different subsets of functionailty. It's hard to see how to
make this into an extensible framework.
The template-based IDL will make this stuff easier.
>> However, most of this stuff is
>> useful only at compile time.
>
> I showed above how the first two are useful at run-time. size_of() is
> useful when writing code which is type-checked at run-time. It is
> important for making dynamically typed algorithms more efficient. The
> other two, I can't think of applications yet.
Could you give an example?
>>>> I'm thinking of adding a template boost::interfaces::any, which has
>>>> (I think boost::interfaces::null might be a better name for
>>>> IAnything.)
>>>
>>> How about IUnknown? It will be especially meaningful when
>>> boost::interfaces allow dynamic introspection.
>>
>> Even when reflection is added, you'll only be able to query the functions of
>> the interface; you won't be able to bind the underlying object to an
>> interface discovered at runtime -- unless this functionality is
>> built into the class of
>> the bound object.
>
> I realize that, but code like:
>
> int x = extract<int>(null);
>
> would surprise the reader that it works.
It wouldn't work. I was suggesting null as the name of a type, not an object.
> The names that I like:
>
> IEmpty
> IAnything
> IUnknown
> INull
I'm not sure the name matters much, because it would usually be left
unspecified:
template<typename Interface = null>
class any;
std::string s = "hello";
any<> a = s;
any<iterator> it = s.begin();
Also, while I've been using the microsoft interface naming convention for
example interfaces, it violates the Boost guidelines for library classes.
Jonathan