
Hello all, I just realized that an empty BIL interface, BOOST_IDL_BEGIN(IAnything) BOOST_IDL_EMPTY(IAnything) has some common ground with: boost::any Where boost::any stores a copy of a value of practical any type for later extraction, IAnything can point to just about anything. void BoostAnyTest() { int x = 5; boost::any a = x; TEST(any_cast<int>(a) == 5); } void AnythingTest() { int x = 5; IAnything a = x; TEST(extract<int>(a) == 5); } void ObjectTests() { BoostAnyTest(); AnythingTest(); } I just thought this could lead to some kind of connection between the libraries. It might be nice to see this in the boost::any namespace, i.e. a boost::any::any_ref. Christopher Diggins Object Oriented Template Library (OOTL) http://www.ootl.org

christopher diggins wrote:
Hello all,
I just realized that an empty BIL interface,
BOOST_IDL_BEGIN(IAnything) BOOST_IDL_EMPTY(IAnything)
has some common ground with:
boost::any
Where boost::any stores a copy of a value of practical any type for later extraction, IAnything can point to just about anything.
Yes, I noticed this just a few days ago ;-) One can think of smart references as generalizations of any in which - the ownership policy can vary; e.g., it could be reference-counted instead of clone-on-copy - the type of admissible objects can restricted using interfaces - the syntax for binding is slightly different For instance, a reference-counted any that can bind to anything is shared_obj<IAnything>. I'm thinking of adding a template boost::interfaces::any, which has cloning semantics and uses the same syntax as any for binding, i.e., assignment and construction from a const reference. template<typename Interface = IAnything> class any; (I think boost::interfaces::null might be a better name for IAnything.) However, maybe what is needed instead is just a policy-based smart reference. Jonathan

----- Original Message ----- From: "Jonathan Turkanis" <technews@kangaroologic.com> To: <boost@lists.boost.org> Sent: Friday, January 28, 2005 6:00 PM Subject: [boost] Re: BIL and boost::any
One can think of smart references as generalizations of any in which
- the ownership policy can vary; e.g., it could be reference-counted instead of clone-on-copy - the type of admissible objects can restricted using interfaces - the syntax for binding is slightly different
For instance, a reference-counted any that can bind to anything is shared_obj<IAnything>.
Would it be a reasonable request then to have clone(interface_value)? Would make sense to also have dynamic traits, i.e. is_clonesable(interface_value). This seems to be pointing down a path of never ending feature requests to interface. I think it would be nice to lay down an easily extendible interface type. I mentioned earlier about allowing users to extend interface types. One way which I would like to extend interface types is to have an interface type which provides an extra function: Usage: dynamic_traits traits = extract_traits(interface_value); dyanmic_traits could be a class which provides run-time functions like: is_copy_constructible(); is_default_constructible(); size_of(); is_primitive(); is_integral(); etc.
I'm thinking of adding a template boost::interfaces::any, which has cloning semantics and uses the same syntax as any for binding, i.e., assignment and construction from a const reference.
template<typename Interface = IAnything> class any;
(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.
However, maybe what is needed instead is just a policy-based smart reference.
That would be a good thing. Excited about C++ again, Christopher

christopher diggins wrote:
----- Original Message ----- From: "Jonathan Turkanis" <technews@kangaroologic.com> To: <boost@lists.boost.org> Sent: Friday, January 28, 2005 6:00 PM Subject: [boost] Re: BIL and boost::any
One can think of smart references as generalizations of any in which
- the ownership policy can vary; e.g., it could be reference-counted instead of clone-on-copy - the type of admissible objects can restricted using interfaces - the syntax for binding is slightly different
For instance, a reference-counted any that can bind to anything is shared_obj<IAnything>.
Would it be a reasonable request then to have clone(interface_value)?
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.
Would make sense to also have dynamic traits, i.e. is_clonesable(interface_value). This seems to be pointing down a path of never ending feature requests to interface. I think it would be nice to lay down an easily extendible interface type. I mentioned earlier about allowing users to extend interface types. One way which I would like to extend interface types is to have an interface type which provides an extra function:
I don't really understand.
Usage:
dynamic_traits traits = extract_traits(interface_value);
dyanmic_traits could be a class which provides run-time functions like:
is_copy_constructible(); is_default_constructible(); size_of(); is_primitive(); is_integral(); etc.
You could determine this stuff (to the extent the language allows) at the time of binding, and make it available at runtime. However, most of this stuff is useful only at compile time.
I'm thinking of adding a template boost::interfaces::any, which has cloning semantics and uses the same syntax as any for binding, i.e., assignment and construction from a const reference.
template<typename Interface = IAnything> class any;
(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.
However, maybe what is needed instead is just a policy-based smart reference.
That would be a good thing.
I'm thinking now that smart references should have syntax like boost::any instead of smart pointer syntax. They could be called smart interfaces.
Excited about C++ again,
:-)
Christopher
Jonathan

----- Original Message ----- From: "Jonathan Turkanis" <technews@kangaroologic.com>
christopher diggins wrote:
----- Original Message ----- From: "Jonathan Turkanis" <technews@kangaroologic.com> To: <boost@lists.boost.org> Sent: Friday, January 28, 2005 6:00 PM Subject: [boost] Re: BIL and boost::any
For instance, a reference-counted any that can bind to anything is shared_obj<IAnything>.
Would it be a reasonable request then to have clone(interface_value)?
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. I am not sure I understand what you mean by making cloning as just another functio. I also don't think Clone is unique. Clone is essentially a call to the copy constructor of the object, but there could also be a similar call to the default constructor. Conceptually I would group the default ctor, copy ctor, and destructor, together. These are the member functions which can't be pointed to. So I would propose (renaming Clone to new_copy): AnyInterface i = AnyObject; //... if (has_copy_ctor(i) && has_dtor(i)) { manual_ptr<AnyInterface> p = new_copy(i); } also: AnyInterface i = AnyObject; //... if (has_default_ctor(i) && has_dtor(i)) { manual_ptr<AnyInterface> p = new_default_ctor(i); } Both pieces of code above are extremely useful, especially if we want interfaces to have the same expressive power as boost::any. 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?).
Would make sense to also have dynamic traits, i.e. is_clonesable(interface_value). This seems to be pointing down a path of never ending feature requests to interface. I think it would be nice to lay down an easily extendible interface type. I mentioned earlier about allowing users to extend interface types. One way which I would like to extend interface types is to have an interface type which provides an extra function:
I don't really understand.
Usage:
dynamic_traits traits = extract_traits(interface_value);
dyanmic_traits could be a class which provides run-time functions like:
is_copy_constructible(); is_default_constructible(); size_of(); is_primitive(); is_integral(); etc.
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 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, 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.
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.
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 is reasonable to expect null to contain virtually no extra information, let alone a reference to a live object. The names that I like: IEmpty IAnything IUnknown INull best regards, Christopher Diggins Object Oriented Template Library (OOTL) http://www.ootl.org

christopher diggins wrote:
----- Original Message ----- From: "Jonathan Turkanis" <technews@kangaroologic.com>
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

Jonathan Turkanis wrote:
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.
I stuck this last sentence in the wrong place. As long as the extra functions have to be declared in an interface, there should be no unnecessary bloat, assuming you don't declare them if you don't need them. Jonathan

----- Original Message ----- From: "Jonathan Turkanis" <technews@kangaroologic.com>
You mean it should be defined in the global namespace? Defining stuff in the global namespace *causes* clashes.
Sorry, I meant "not a member function".
As a result, a more general treatment, like Thorsten's, is needed.
I see.
I prefer clone(), since it is an established name.
I agree now.
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.
Could this not be done using by constructing static functions at compile-time which call: ::boost::has_nothrow_copy<T>::value ::boost::has_trivial_destructor<T>::value
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.
Yes, this is a good reason to leave it up to the user to decide.
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.
Yes, I didn't mean to make it sound that way.
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.
Next email.
I'll certainly implement cloning, one way or another. I'm not yet convinced of the value of default construction, though.
I don't have any use cases at the moment but I also don't care that much about default constructible for the time being.
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
I agree, it is a hard problem, but not overcomeable.
- 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.
I have some ideas on how to do this, but it will have to wait until my next post.
The template-based IDL will make this stuff easier.
Agreed.
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?
Of size_of? Ummm... next email.
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.
Yes, sorry.
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();
What about code like: FuBar(null n) { if (n.type_info() == typeid(int)) { cout << extract<int>(n); } } I would rather say: FuBar(IAnything n) { if (n.type_info() == typeid(int)) { cout << extract<int>(n); } } Whatever, this is trivial stuff, I don't really care that much.
Also, while I've been using the microsoft interface naming convention for example interfaces, it violates the Boost guidelines for library classes.
Shucks, maybe Boost should update its guidelines ;) best, CD

christopher diggins wrote:
----- Original Message ----- From: "Jonathan Turkanis" <technews@kangaroologic.com>
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.
Could this not be done using by constructing static functions at compile-time which call:
boost::has_nothrow_copy<T>::value boost::has_trivial_destructor<T>::value
These traits require special compiler support (e.g. they always return false on VC7.1) and don't query the correct properties (e.g. for a class to have a *trivial* destructor, it must not declare a destructor, among other things).
I don't think Boost.Any ever assumes that user defined types are default constructible.
Yes, I didn't mean to make it sound that way.
Okay.
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
I agree, it is a hard problem, but not overcomeable.
- 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.
I have some ideas on how to do this, but it will have to wait until my next post.
Okay. I look forward to it ;-)
The template-based IDL will make this stuff easier.
Agreed.
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?
Of size_of?
Yes.
FuBar(null n) { if (n.type_info() == typeid(int)) { cout << extract<int>(n); } }
I would rather say:
FuBar(IAnything n) { if (n.type_info() == typeid(int)) { cout << extract<int>(n); } }
Yes, null looks a little funny here. BTW, it should be target_type(n) == typeid(int) Jonathan

christopher diggins wrote:
The template-based IDL will make this stuff easier.
Agreed.
Is there a non-macro-based variant of the IDL in development, or is this referring to the implementation behind the macros? If the first, sorry that I missed it. Could you please give me a link? <snip>
The names that I like:
IEmpty IAnything IUnknown INull
I find all of these distrurbingly reminiscent of COM interfaces...
I would rather say:
FuBar(IAnything n) { if (n.type_info() == typeid(int)) { cout << extract<int>(n); } }
Whatever, this is trivial stuff, I don't really care that much.
I beg to differ, and I am sure many others will along with me :) My preference is for 'unknown', since you don't know anything about the type. FuBar(unknown obj) { if (target_type(obj) == typeid(int)) { cout << extract<int>(obj); } } Matt

Matthew Vogt wrote:
christopher diggins wrote:
The template-based IDL will make this stuff easier.
Agreed.
Is there a non-macro-based variant of the IDL in development,
Yes, but I haven't had much time to work on it. See http://tinyurl.com/6w59y.
<snip>
The names that I like:
IEmpty IAnything IUnknown INull
I find all of these distrurbingly reminiscent of COM interfaces...
I intended the reminiscence but not the disturbance. :-)
I would rather say:
FuBar(IAnything n) { if (n.type_info() == typeid(int)) { cout << extract<int>(n); } }
Whatever, this is trivial stuff, I don't really care that much.
I beg to differ, and I am sure many others will along with me :)
My preference is for 'unknown', since you don't know anything about the type.
FuBar(unknown obj) { if (target_type(obj) == typeid(int)) { cout << extract<int>(obj); } }
I don't really have a preference between "anything" and "unknown", but I would have thought the former would be less disturbing. ;-) Jonathan

Yes, but I haven't had much time to work on it. See http://tinyurl.com/6w59y.
Ok, thanks.
I find all of these distrurbingly reminiscent of COM interfaces...
I intended the reminiscence but not the disturbance. :-)
Isn't it interesting that the mere use of a naming convention can evoke trepidation of the coding style you associate with that naming convention? Anyhow, my problem with the macro-based IDL is that it obscures the function signatures so badly, partly by separating the components so I don't recognise them as a signature, and partly by encasing them in a dense text block. I think that this: BOOST_IDL_BEGIN(Interface) BOOST_IDL_CONST_FN2(print, void, ostream&, int) BOOST_IDL_END(Interface) is readability-wise so far away from: struct Interface { void print(ostream&, int) const; }; that it is an enormous hurdle for BIL to overcome. The template-based IDL theorised in your docs seems much closer to what I would like: typedef interface< function<print, void (ostream&, int)> const
Interface;
There doesn't seem to be much support for this in the tarball, though. Do you have any experimental code for defining these interfaces? If not, do you forsee major issues in implementing them later? Thanks, Matt -- Matthew Vogt mattvogt@warpmail.net

Matthew Vogt wrote:
Anyhow, my problem with the macro-based IDL is that it obscures the function signatures so badly, partly by separating the components so I don't recognise them as a signature, and partly by encasing them in a dense text block.
I think that this:
BOOST_IDL_BEGIN(Interface) BOOST_IDL_CONST_FN2(print, void, ostream&, int) BOOST_IDL_END(Interface)
is readability-wise so far away from:
struct Interface { void print(ostream&, int) const; };
that it is an enormous hurdle for BIL to overcome.
I'm sympathetic to this point of view. The reason it doesn't seem so bad to me is that only a relatively small part of coding with BIL is actually defining interfaces; the code which uses the interfaces is just ordinary C++. Do you have any suggestions for improving the macro syntax? For instance, do you like David Abrahams's suggested syntax better: DECLARE_INTERFACE( Interface, ((int)(print)(ostream&)(int)) ); ? (I'm not sure where to stick 'const')
The template-based IDL theorised in your docs seems much closer to what I would like:
typedef interface< function<print, void (ostream&, int)> const
Interface;
There doesn't seem to be much support for this in the tarball, though.
Right, there isn't any.
Do you have any experimental code for defining these interfaces?
I've started work on it, but it doesn't work yet.
If not, do you forsee major issues in implementing them later?
I'm sure it is theoretically correct, and am optimistic that it will work in practice because it uses the same techniques as the macro-based approach. However I can't say for sure that it will work until I see it.
Thanks, Matt
Jonathan

Jonathan Turkanis wrote:
Matthew Vogt wrote:
Anyhow, my problem with the macro-based IDL is that it obscures the function signatures so badly, partly by separating the components so I don't recognise them as a signature, and partly by encasing them in a dense text block.
I think that this:
BOOST_IDL_BEGIN(Interface) BOOST_IDL_CONST_FN2(print, void, ostream&, int) BOOST_IDL_END(Interface)
is readability-wise so far away from:
struct Interface { void print(ostream&, int) const; };
that it is an enormous hurdle for BIL to overcome.
I'm sympathetic to this point of view. The reason it doesn't seem so bad to me is that only a relatively small part of coding with BIL is actually defining interfaces; the code which uses the interfaces is just ordinary C++.
Do you have any suggestions for improving the macro syntax? For instance, do you like David Abrahams's suggested syntax better:
DECLARE_INTERFACE( Interface, ((int)(print)(ostream&)(int)) );
?
(I'm not sure where to stick 'const')
Or the one I use for my project... INHERITED(INTERFACE(DataTransferEvent),Event) ENUM(DataTransferEventType) NAME(Type VALUE(0x003)) ENUM_CLOSE ENUM(Request) NAME(DataExtent) NAME(Data) NAME(Complete) ENUM_CLOSE METHOD(DataTransferEvent::Request,getRequest,ARGS0,throw()) VOID_METHOD(getRequestData,ARGS2(UInt64&,UInt64&),throw()) VOID_METHOD(readDataExtent,ARGS1(UInt64&),throw()) VOID_METHOD(readData,ARGS3(UInt64&,UInt64&,Pointer&),throw()) METHOD(bool,isComplete,ARGS0,throw()) VOID_METHOD(setDataExtent,ARGS1(UInt64),throw()) VOID_METHOD(setData,ARGS3(UInt64,UInt64,Pointer),throw()) VOID_METHOD(setComplete,ARGS0,throw()) INTERFACE_CLOSE INTERFACE(Exception) METHOD(UString,getMessage,ARGS0,throw()) METHOD(UString,getDescription,ARGS0,throw()) DECLARE_NESTED(INTERFACE(PreconditionViolation)) DECLARE_NESTED(INTERFACE(InvalidArgument)) DECLARE_NESTED(INTERFACE(InvalidResult)) INTERFACE_CLOSE (and many more.. documentation comments and whitespace elided) -- -- Grafik - Don't Assume Anything -- Redshift Software, Inc. - http://redshift-software.com -- rrivera/acm.org - grafik/redshift-software.com - 102708583/icq

Rene Rivera wrote:
Jonathan Turkanis wrote:
Matthew Vogt wrote:
Or the one I use for my project...
INHERITED(INTERFACE(DataTransferEvent),Event) ENUM(DataTransferEventType) NAME(Type VALUE(0x003)) ENUM_CLOSE ENUM(Request) NAME(DataExtent) NAME(Data) NAME(Complete) ENUM_CLOSE METHOD(DataTransferEvent::Request,getRequest,ARGS0,throw()) VOID_METHOD(getRequestData,ARGS2(UInt64&,UInt64&),throw()) VOID_METHOD(readDataExtent,ARGS1(UInt64&),throw()) VOID_METHOD(readData,ARGS3(UInt64&,UInt64&,Pointer&),throw()) METHOD(bool,isComplete,ARGS0,throw()) VOID_METHOD(setDataExtent,ARGS1(UInt64),throw()) VOID_METHOD(setData,ARGS3(UInt64,UInt64,Pointer),throw()) VOID_METHOD(setComplete,ARGS0,throw()) INTERFACE_CLOSE INTERFACE(Exception) METHOD(UString,getMessage,ARGS0,throw()) METHOD(UString,getDescription,ARGS0,throw()) DECLARE_NESTED(INTERFACE(PreconditionViolation)) DECLARE_NESTED(INTERFACE(InvalidArgument)) DECLARE_NESTED(INTERFACE(InvalidResult)) INTERFACE_CLOSE
Unfortunately, once you switch to the boost macro-naming conventions, having a macros to declare the argument list becomes a bit verbose: BOOST_IDL_VOID_METHOD(readData,BOOST_IDL_ARGS3(UInt64&,UInt64&,Pointer&)) I guess you could have the outer macro stick the prefix on the inner macro, so there wouldn't really be any ARGn macros. Is that what you do? The project you mention looks interesting. What sort of interfaces are you generating? Jonathan

Jonathan Turkanis wrote:
Rene Rivera wrote:
INHERITED(INTERFACE(DataTransferEvent),Event) ENUM(DataTransferEventType) NAME(Type VALUE(0x003)) METHOD(DataTransferEvent::Request,getRequest,ARGS0,throw()) VOID_METHOD(getRequestData,ARGS2(UInt64&,UInt64&),throw()) VOID_METHOD(readDataExtent,ARGS1(UInt64&),throw()) VOID_METHOD(readData,ARGS3(UInt64&,UInt64&,Pointer&),throw()) INTERFACE_CLOSE
Unfortunately, once you switch to the boost macro-naming conventions, having a macros to declare the argument list becomes a bit verbose:
BOOST_IDL_VOID_METHOD(readData,BOOST_IDL_ARGS3(UInt64&,UInt64&,Pointer&))
I guess you could have the outer macro stick the prefix on the inner macro, so there wouldn't really be any ARGn macros. Is that what you do?
Something like that.. I have a Def.h to define the bare macros in terms of fully prefixed macros, THOT_* in my case, and a corresponding Undef.h to clear things out. The Def.h takes care to prepend the prefix only when needed, and the individual outer macros will prepend the inner ones as needed. It's a round about way of doing it but it has the benefit of: a) having the real macros defined once, b) the real macros are much easier to read, c) the outer layer can take care of PP problems (like for CW8).
The project you mention looks interesting. What sort of interfaces are you generating?
I current use them to generate: 1. Public header only PIMPL API to all my DLLs/SOs. 2. Private header PIMPL implementation declarations to all my DLLs/SOs. 3. Private source PIMPL implementation to forward to implementation classes. 4. Lua bindings to my API using LuaBind. All that is done by changing only the definition of the inner macros. To produce the code I'm looking for. For example here's the file to do the Lua binding for the above DataTransferEvent interface.. ===BindDataTransferEvent.cpp=== /* Copyright (c) 2003 Redshift Software, Inc. All Rights Reserved. */ #include <com/redshift-software/projects/Thot/product/plugins/lua5_script/lua_def.h> #include <com/redshift-software/projects/Thot/product/api/All.h> #include <com/redshift-software/projects/Thot/product/plugins/lua5_script/Imp.h> #undef com_redshift_software_projects_thot_product_api_datatransferevent_h #include <com/redshift-software/projects/Thot/product/api/DataTransferEvent.h> ===.=== [Imp.h is the one that defines the inner macros in this case] That alone was worth all the effort of implementing a PP based IDL -- I once even tried to bind my complete API in a single file like the above, but that ground the compiler to a halt when it tried to use a few magnitudes more memory than I have :-) -- -- Grafik - Don't Assume Anything -- Redshift Software, Inc. - http://redshift-software.com -- rrivera/acm.org - grafik/redshift-software.com - 102708583/icq

On Tue, 1 Feb 2005 20:37:18 -0700, "Jonathan Turkanis" <technews@kangaroologic.com> said:
I'm sympathetic to this point of view. The reason it doesn't seem so bad to me is that only a relatively small part of coding with BIL is actually defining interfaces; the code which uses the interfaces is just ordinary C++.
Yeah, but in order to write any ordinary C++ using an interface, you must first (mentally) parse the interface. Yes, you won't write much IDL, but it will be read many times...
Do you have any suggestions for improving the macro syntax? For instance, do you like David Abrahams's suggested syntax better:
DECLARE_INTERFACE( Interface, ((int)(print)(ostream&)(int)) );
Maybe it will grow on me :)
Do you have any experimental code for defining these interfaces?
I've started work on it, but it doesn't work yet.
I hope it comes together.
If not, do you forsee major issues in implementing them later?
I'm sure it is theoretically correct, and am optimistic that it will work in practice because it uses the same techniques as the macro-based approach. However I can't say for sure that it will work until I see it.
I'm glad to hear your optimism, anyway. BTW, cool library. Thanks, Matt -- Matthew Vogt mattvogt@warpmail.net

Matthew Vogt wrote:
On Tue, 1 Feb 2005 20:37:18 -0700, "Jonathan Turkanis" <technews@kangaroologic.com> said:
I'm sympathetic to this point of view. The reason it doesn't seem so bad to me is that only a relatively small part of coding with BIL is actually defining interfaces; the code which uses the interfaces is just ordinary C++.
Yeah, but in order to write any ordinary C++ using an interface, you must first (mentally) parse the interface.
True.
Yes, you won't write much IDL, but it will be read many times...
You can always write the pseudocode together with the interface: /* struct Interface { void print(ostream&, int) const; }; */ BOOST_IDL_BEGIN(Interface) BOOST_IDL_CONST_FN2(print, void, ostream&, int) BOOST_IDL_END(Interface) Of course, you run the risk that they will get out of sync.
BTW, cool library.
Thanks.
Matt
Jonathan

Jonathan Turkanis wrote:
Do you have any suggestions for improving the macro syntax? For instance, do you like David Abrahams's suggested syntax better:
DECLARE_INTERFACE( Interface, ((int)(print)(ostream&)(int)) );
?
Here's two other ideas (that I *think* are implementable): DECLARE_INTERFACE(Interface, 2(int, print, (ostream&, int)) ); DECLARE_INTERFACE(Interface, (int, print, 2(ostream&, int)) ); -- Daniel Wallin

Daniel Wallin wrote:
Jonathan Turkanis wrote:
Do you have any suggestions for improving the macro syntax? For instance, do you like David Abrahams's suggested syntax better:
DECLARE_INTERFACE( Interface, ((int)(print)(ostream&)(int)) );
?
Here's two other ideas (that I *think* are implementable):
DECLARE_INTERFACE(Interface, 2(int, print, (ostream&, int)) );
DECLARE_INTERFACE(Interface, (int, print, 2(ostream&, int)) );
This is a bit like Rene's, with 'ARGn' replaced by plain 'n'. If I could just get rid of that damned arity everything would be great! Jonathan

"Jonathan Turkanis" <technews@kangaroologic.com> writes:
Daniel Wallin wrote:
Jonathan Turkanis wrote:
Do you have any suggestions for improving the macro syntax? For instance, do you like David Abrahams's suggested syntax better:
DECLARE_INTERFACE( Interface, ((int)(print)(ostream&)(int)) );
?
Here's two other ideas (that I *think* are implementable):
DECLARE_INTERFACE(Interface, 2(int, print, (ostream&, int)) );
DECLARE_INTERFACE(Interface, (int, print, 2(ostream&, int)) );
This is a bit like Rene's, with 'ARGn' replaced by plain 'n'.
If I could just get rid of that damned arity everything would be great!
DECLARE_INTERFACE(Interface, (int, print, (ostream&)(int)) ); ? -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
"Jonathan Turkanis" <technews@kangaroologic.com> writes:
Daniel Wallin wrote:
Jonathan Turkanis wrote:
Do you have any suggestions for improving the macro syntax? For instance, do you like David Abrahams's suggested syntax better:
DECLARE_INTERFACE( Interface, ((int)(print)(ostream&)(int)) );
DECLARE_INTERFACE(Interface, (int, print, 2(ostream&, int)) );
If I could just get rid of that damned arity everything would be great!
DECLARE_INTERFACE(Interface, (int, print, (ostream&)(int)) );
?
This might be the best one yet. The same basic idea as your earlier suggestion, but without two of the annoying sets of parentheses. If you can help me figure out where to stick 'const' I'll be ready to roll. :-) Jonathan

"Jonathan Turkanis" <technews@kangaroologic.com> writes:
David Abrahams wrote:
"Jonathan Turkanis" <technews@kangaroologic.com> writes:
Daniel Wallin wrote:
Jonathan Turkanis wrote:
Do you have any suggestions for improving the macro syntax? For instance, do you like David Abrahams's suggested syntax better:
DECLARE_INTERFACE( Interface, ((int)(print)(ostream&)(int)) );
DECLARE_INTERFACE(Interface, (int, print, 2(ostream&, int)) );
If I could just get rid of that damned arity everything would be great!
DECLARE_INTERFACE(Interface, (int, print, (ostream&)(int)) );
?
This might be the best one yet. The same basic idea as your earlier suggestion, but without two of the annoying sets of parentheses. If you can help me figure out where to stick 'const' I'll be ready to roll. :-)
You mean member function constness? Sorry, I don't know. Maybe Paul M. has some ideas -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
"Jonathan Turkanis" writes:
David Abrahams wrote:
"Jonathan Turkanis" writes:
If I could just get rid of that damned arity everything would be great!
DECLARE_INTERFACE(Interface, (int, print, (ostream&)(int)) ); ? This might be the best one yet. The same basic idea as your earlier suggestion, but without two of the annoying sets of parentheses. If you can help me figure out where to stick 'const' I'll be ready to roll. :-)
You mean member function constness?
Yeah, that's what I meant. I'm willing to overlook volatile.
Sorry, I don't know. Maybe Paul M. has some ideas
Okay, I'll email him. Jonathan

Jonathan Turkanis writes:
christopher diggins wrote:
Hello all,
I just realized that an empty BIL interface,
BOOST_IDL_BEGIN(IAnything) BOOST_IDL_EMPTY(IAnything)
has some common ground with:
boost::any
Where boost::any stores a copy of a value of practical any type for later extraction, IAnything can point to just about anything.
Yes, I noticed this just a few days ago ;-)
[...]
I'm thinking of adding a template boost::interfaces::any, which has cloning semantics and uses the same syntax as any for binding, i.e., assignment and construction from a const reference.
template<typename Interface = IAnything> class any;
Are you aware of Alexander Nasonov's work on "dynamic_any" (http://cpp-experiment.sourceforge.net/boost/libs/dynamic_any/doc/tutorial.ht... -- Aleksey Gurtovoy MetaCommunications Engineering

Aleksey Gurtovoy wrote:
Jonathan Turkanis writes:
I'm thinking of adding a template boost::interfaces::any, which has cloning semantics and uses the same syntax as any for binding, i.e., assignment and construction from a const reference.
template<typename Interface = IAnything> class any;
Are you aware of Alexander Nasonov's work on "dynamic_any"
(http://cpp-experiment.sourceforge.net/boost/libs/dynamic_any/doc/tutorial.ht...) ? Yes, in fact I borrowed the extract function from dynamic_any. There seem to be some close connections between dynamic_any and the interface library, but I'm not yet sure what they are. ;-) Jonathan
participants (7)
-
Aleksey Gurtovoy
-
christopher diggins
-
Daniel Wallin
-
David Abrahams
-
Jonathan Turkanis
-
Matthew Vogt
-
Rene Rivera