Can't get PocoCapsule to work with a factory-method that returns a smart pointer

12 views
Skip to first unread message

bra...@gmail.com

unread,
Jan 26, 2009, 3:05:11 PM1/26/09
to pococapsule
Hi,

I'm really interested in PocoCapsule. I think it could be a great way
to integrate all the pieces of a software framework developed by the
group I work with.

So, I'm trying it out with the framework, but am having trouble
because our object factories return pointers wrapped in the
boost::shared_ptr "smart pointer" object. (If you're not familiar
with this, it's a template type that wraps a pointer, and acts like
that pointer, but adds internal reference counting and handles
deleting the pointer once no other objects are using it. It acts like
a pointer by implementing the * and -> operators. See
http://www.boost.org/doc/libs/1_36_0/libs/smart_ptr/shared_ptr.htm for
more info.)

For example, the factory looks something like this (NOTE: this is not
actual code, but it's very close):

class Foo { ... }; // abstract type

class SpecificFoo : public Foo { ... }; // one of several sub-types of
Foo

typedef boost::shared_ptr<Foo> FooPtr;

class FooFactory {
virtual FooPtr create( ... );
};

In my setup.xml I have something like this (except for the word "foo",
this is accurate):

<bean id="fooFactory" class="FooFactory"
singleton="true" lazy-init="true"
destroy-method="delete"
/>

<bean id="foo" class="*FooPtr"
singleton="true" lazy-init="false"
factory-bean="fooFactory" factory-method="create"
destroy-method="delete"
>
<method-arg ... /> <!-- there is one argument, but I doubt the
details matter here -->
</bean>

I used "*FooPtr" as the class for the "foo" bean, based on section
3.2.1 of the Developer's Guide (p. 30). I would think that this is
allowed since FooPtr does act like (Foo*). However, when the
generated setup_reflx.cpp file is compiled (in Windows or Linux), the
compiler complains, saying it cannot convert 'FooPtr' to 'void *'.

I tried changing the "foo" bean class attribute from "*FooPtr" to just
plain "FooPtr" in setup.xml, but the compilers still complain, saying
they cannot convert 'IO_ConnectionPtr' to 'IO_ConnectionPtr*'.

Am I misunderstanding something? Does PocoCapsule work with smart
pointers?

I know I could probably make it work by changing the factory to return
a raw Foo* instead of the smart pointer, but the factory is used for
other purposes (not just PocoCapsule), and raw pointers go against my
group's programming practices.

Any advice will be much appreciated.

Thanks in advance, and thanks for the work on PocoCapsule,
-- Bryan Raney

Ke Jin

unread,
Jan 27, 2009, 1:36:04 AM1/27/09
to pococapsule
Hi Bryan,

See my inline response.

Ke
This is not correct. FooPtr is an class type rather than a pointer
type. So, you should declare class="FooPtr" instead of
class="*FooPtr".

> I used "*FooPtr" as the class for the "foo" bean, based on section
> 3.2.1 of the Developer's Guide (p. 30).

The MyFuncPtr in the section 3.2.1 of Dev Guide is a pointer type,
i.e.

void (*MyFuncPtr)(...);

Similarly, in other examples, the CORBA::Object_ptr is also a pointer
type, i.e.

typedef Object* Object_ptr;

They are different from the FooPtr, which is a class type instead of a
pointer type.

> I would think that this is
> allowed since FooPtr does act like (Foo*).

By certain operator overload (especially the -> operator), FooPtr does
have similar syntax to Foo* in certain cases. However, this does not
mean it is a pointer type and same as Foo*. Most importantly, a FooPtr
can't be implicitly (and safely) casted to Foo* and certainly can't be
cast to void* either.

> However, when the
> generated setup_reflx.cpp file is compiled (in Windows or Linux), the
> compiler complains, saying it cannot convert 'FooPtr' to 'void *'.
>
> I tried changing the "foo" bean class attribute from "*FooPtr" to just
> plain "FooPtr" in setup.xml, but the compilers still complain, saying
> they cannot convert 'IO_ConnectionPtr' to 'IO_ConnectionPtr*'.
>
> Am I misunderstanding something? Does PocoCapsule work with smart
> pointers?
>

PocoCapsule works with smart pointers in many cases. For instance, in
CORBA, and WS examples. However, in the current release, PocoCapsule
requires factories to return by pointer. Factory returning by value or
reference is not explicitly supported.

> I know I could probably make it work by changing the factory to return
> a raw Foo* instead of the smart pointer, but the factory is used for
> other purposes (not just PocoCapsule), and raw pointers go against my
> group's programming practices.
>
> Any advice will be much appreciated.
>

I would suggest the following approach that allows you to use FooPtr
instead of the raw pointer Foo*:

define a factory wrapper in a header file (e.g. FooPtrFactory.h) as:

FooPtrFactory {
FooFactory& _fooFactory;
public:
FooPtrFactory(FooFactory& f) : _fooFactory(f) {}
FooPtr* create(....) {
FooPtr* pptr = new FooPtr(_fooFactory.create(....));
return pptr;
}
};

Then, in setup.xml

<!-- your original FooFactory singleton -->
<bean id="fooFactory" class="FooFactory"
singleton="true" lazy-init="true"
destroy-method="delete"
/>

<!-- an additonal FooPtrFactory singleton -->
<bean id=fooPtrFactory" class="FooPtrFactory"
singleton="true" lazy-init="true"
destroy-method="delete"
>
<method-arg pass="deref" ref="fooFactory"/>
</bean>

<!-- use the fooPtrFactory instead of the fooFactory -->
<bean id="foo" class="FooPtr"
singleton="true" lazy-init="false"
factory-bean="fooPtrFactory" factory-method="create"
destroy-method="delete"
>
<method-arg ... /> <!-- there is one argument, but I doubt the
details matter here -->
</bean>

Then (!!), run the pxgenproxy tool with "-h=fooPtrFactory.h" as a
command line argument to insert a line of

#include <fooPtrFactory.h>

in the generated proxy code (see the makefile of basic-ioc/stl_map).

Supporting smart pointers as factory return values explicitly in
PocoCapsule should require minimum works. Basically the boilerplate
code of FooPtrFactory::create(...) in above example can be
automatically generated by pxgenproxy (this assumes the FooPtr defines
a copy ctor). This was considered during early design but was
eventually dropped due to the programming practice of CORBA world
where even smart pointers (i.e. _var classes) are widely used,
factories are commonly return raw pointers instead of smart pointers.
If factories returning smart pointers is a common programming
practice, I will reconsider to explicitly support it in a minor
release.

> Thanks in advance, and thanks for the work on PocoCapsule,

You are very welcome.

Ke

> -- Bryan Raney

bra...@gmail.com

unread,
Jan 28, 2009, 4:52:46 PM1/28/09
to pococapsule
Hi Ke,

Thank you for your quick and thorough response! I will also respond
inline.
OK, thank you for explaining. You are saying that even though the
Boost smart pointer *acts* like a pointer in terms of usage, it is not
an actual pointer. I agree with that. Also, I apparently missed the
line on p. 30 that says "This factory-method must return a pointer
that can be implicitly typecasted to the declared typedef’ed
pointer." The Boost documentation actually says the shared_ptr<T> is
designed to NOT be implicitly typecasted to T*, so my factory method
does not meet the documented requirement for PocoCapsule. At least
now I understand why. :-)

>
> > However, when the
> > generated setup_reflx.cpp file is compiled (in Windows or Linux), the
> > compiler complains, saying it cannot convert 'FooPtr' to 'void *'.
>
> > I tried changing the "foo" bean class attribute from "*FooPtr" to just
> > plain "FooPtr" in setup.xml, but the compilers still complain, saying
> > they cannot convert 'IO_ConnectionPtr' to 'IO_ConnectionPtr*'.
>
> > Am I misunderstanding something?  Does PocoCapsule work with smart
> > pointers?
>
> PocoCapsule works with smart pointers in many cases. For instance, in
> CORBA, and WS examples. However, in the current release, PocoCapsule
> requires factories to return by pointer. Factory returning by value or
> reference is not explicitly supported.

Sorry, I have not looked closely at the CORBA or WS examples, since I
am not familiar with those paradigms and our application does not use
them anyway. (It does make extensive use of dependency injection,
however.)
Wow! Thank you for being so explicit in your example. I have tried
this, and it seems to work, allowing me to use the factory without
changing its code. I discovered one complication to this method,
however. I'll document it here in case anyone else tries this method.

With your method, the "foo" bean is now of type FooPtr*. Since FooPtr
acts like Foo*, that means "foo" now acts like Foo**. In the case
where I want to access Foo itself, I have to be sure to *double-
dereference* the "foo" bean. So, for example, if I want to add an
<ioc> tag to the "foo" bean, I have to be tricky about it.

With my original "foo" bean (assuming it had worked), I would have
done this:
<bean id="foo" class="*FooPtr" ...>
<method-arg ... />
<ioc method="bar" /> <!-- calls foo->bar() -->
</bean>

However, adding that same <ioc> tag to your version of the "foo" bean
causes PocoCapsule to call the bar() method on the FooPtr object,
rather than on the Foo object. FooPtr doesn't have this method, so it
doesn't compile. Instead, I have to do this:

<bean id="foo" class="FooPtr" ...>
<method-arg ... />
<ioc method="get()->bar" /> <!-- calls foo->get()->bar() ;
probably not guaranteed to work -->
</bean>

The get() method of the boost::shared_ptr<Foo> returns Foo*, so that
appending "->bar" turns into the call to bar() on the Foo object.
Whew! Luckily, the way PocoCapsule generates the C++ proxy code
allows this to work as hoped, but I would guess you didn't necessarily
intend to support this method-chaining functionality! :-)

Unfortunately, this little cheat doesn't allow me to use the "foo"
bean in situations where a Foo& is expected. (Our framework's
dependency injection tends to take objects via reference instead of
via smart pointer.)

So, if I have this class:

class FooUser {
FooUser( Foo& myFoo );
};

And it has a bean like this:

<bean id="fooUser" class="FooUser"
singleton="true" lazy-init="false"
destroy-method="delete">
<method-arg type="bean" ref="foo" pass="deref" />
</bean>

It doesn't work, because dereferencing foo once gives FooPtr, but an
actual Foo is needed.

I found a solution that works for both of the above cases. I started
with your "foo" bean (and associated FooPtrFactory), and changed the
id from "foo" to "fooPtr". I then created a new "foo" bean that takes
care of the first dereference, and looks like this:

<bean id="foo" class="Foo"
singleton="true" lazy-init="false"
factory-method="boost::get_pointer"> <!-- no destroy-method;
FooPtr will do the deletion -->
<method-arg type="bean" ref="fooPtr" pass="deref" />
<ioc method="bar" />
</bean>

This bean makes use of the free function "boost::get_pointer()" which
takes a smart pointer and returns the raw pointer it wraps. This
could be a dangerous thing to do, since the boost::shared_ptr can't
keep track of that extra raw pointer copy and could delete it at an
inappropriate time (thinking it's not being used anymore). But I'm
expecting that PocoCapsule won't destroy the "fooPtr" bean while the
"foo" bean that depends on it is in use.

Since the new "foo" bean is a Foo* (the actual pointer, not a class),
I can call Foo's methods on it, and deref it when passing to FooUser.

>
> Supporting smart pointers as factory return values explicitly in
> PocoCapsule should require minimum works. Basically the boilerplate
> code of FooPtrFactory::create(...) in above example can be
> automatically generated by pxgenproxy (this assumes the FooPtr defines
> a copy ctor). This was considered during early design but was
> eventually dropped due to the programming practice of CORBA world
> where even smart pointers (i.e. _var classes) are widely used,
> factories are commonly return raw pointers instead of smart pointers.
> If factories returning smart pointers is a common programming
> practice, I will reconsider to explicitly support it in a minor
> release.

I don't know how common the practice of returning smart pointers from
factories might be. I certainly expect the use of smart pointers
(especially Boost's) to grow in the future. Boost's smart pointer
classes are part of the TR1 addition to the standard C++ library, and
are advocated in _Effective_C++_ by Scott Meyers. Plus, it makes a
lot of sense (to me anyway) to have factories return safer, wrapped
pointers, instead of raw pointers that have to be manually wrapped by
the receiver upon creation (which makes memory leaks more likely).

I hope that if you do decide to support this kind of factory in a
future version of PocoCapsule, that you also arrange for the generated
proxies to automatically dereference the pointer-to-shared-pointer
back into a shared-pointer, so that the additional (and possibly
dangerous) dereferencing step I showed above is not necessary.

Thanks again,
-- Bryan Raney

P.S. In case it helps you, I have learned that a boost::shared_ptr<T>
can be converted to boost::shared_ptr<void>, to mimic the use of void*
to store any type. (See http://www.boost.org/doc/libs/1_37_0/libs/smart_ptr/sp_techniques.html#pvoid
for more info.)

Ke Jin

unread,
Jan 29, 2009, 12:45:24 AM1/29/09
to pococapsule
On Jan 28, 1:52 pm, bra...@gmail.com wrote:
> Hi Ke,
>
> Thank you for your quick and thorough response! I will also respond
> inline.
>

You are very welcome. Also, thanks for your feedback. They will be
seriously considered for further improvement. See my inline notes.

Ke

>
> Wow! Thank you for being so explicit in your example. I have tried
> this, and it seems to work, allowing me to use the factory without
> changing its code. I discovered one complication to this method,
> however. I'll document it here in case anyone else tries this method.
>
> With your method, the "foo" bean is now of type FooPtr*. Since FooPtr
> acts like Foo*, that means "foo" now acts like Foo**. In the case
> where I want to access Foo itself, I have to be sure to *double-
> dereference* the "foo" bean. So, for example, if I want to add an
> <ioc> tag to the "foo" bean, I have to be tricky about it.
>
> With my original "foo" bean (assuming it had worked), I would have
> done this:
> <bean id="foo" class="*FooPtr" ...>
> <method-arg ... />
> <ioc method="bar" /> <!-- calls foo->bar() -->
> </bean>
>

I see your point. I will seriously consider it.

> However, adding that same <ioc> tag to your version of the "foo" bean
> causes PocoCapsule to call the bar() method on the FooPtr object,
> rather than on the Foo object. FooPtr doesn't have this method, so it
> doesn't compile. Instead, I have to do this:
>
> <bean id="foo" class="FooPtr" ...>
> <method-arg ... />
> <ioc method="get()->bar" /> <!-- calls foo->get()->bar() ;
> probably not guaranteed to work -->
> </bean>
>
> The get() method of the boost::shared_ptr<Foo> returns Foo*, so that
> appending "->bar" turns into the call to bar() on the Foo object.
> Whew! Luckily, the way PocoCapsule generates the C++ proxy code
> allows this to work as hoped, but I would guess you didn't necessarily
> intend to support this method-chaining functionality! :-)
>

This is not intended and not recommended, although I some time also
use this tricky (see the basic-ioc/hello example). The recommended
approach is:

<bean id="fooPtr" class="FooPtr"
factory_bean="fooPtrFactory"
factory_method="create"
destroy_method="delete">
<method-arg ..../>
</bean>

<!-- calling foo->bar(). this is same as fooPtr->get()->bar(). -->
<bean class="Foo"
factory_bean="fooPtr"
factory_method="get"
singleton="false" ...>
<ioc method="bar"/>
</bean>

> Unfortunately, this little cheat doesn't allow me to use the "foo"
> bean in situations where a Foo& is expected. (Our framework's
> dependency injection tends to take objects via reference instead of
> via smart pointer.)

My suggested approach above allows you to pass the raw pointer
(encapsulated inside the fooPtr smart pointer object) by reference as:

<bean class="FooUser" ...>
<method-arg ref="foo" pass="deref"/>
</bean>

>
> So, if I have this class:
>
> class FooUser {
> FooUser( Foo& myFoo );
>
> };
>
> And it has a bean like this:
>
> <bean id="fooUser" class="FooUser"
> singleton="true" lazy-init="false"
> destroy-method="delete">
> <method-arg type="bean" ref="foo" pass="deref" />
> </bean>
>
> It doesn't work, because dereferencing foo once gives FooPtr, but an
> actual Foo is needed.
>
> I found a solution that works for both of the above cases. I started
> with your "foo" bean (and associated FooPtrFactory), and changed the
> id from "foo" to "fooPtr". I then created a new "foo" bean that takes
> care of the first dereference, and looks like this:
>
> <bean id="foo" class="Foo"
> singleton="true" lazy-init="false"
> factory-method="boost::get_pointer"> <!-- no destroy-method;
> FooPtr will do the deletion -->
> <method-arg type="bean" ref="fooPtr" pass="deref" />
> <ioc method="bar" />
> </bean>
>

this is almost equivalent to the method I suggested above (except you
define it as a singleton with id), i.e. using the get() to retrieve
the stored pointer foo pointer from the fooPtr.

> This bean makes use of the free function "boost::get_pointer()" which
> takes a smart pointer and returns the raw pointer it wraps. This
> could be a dangerous thing to do, since the boost::shared_ptr can't
> keep track of that extra raw pointer copy and could delete it at an
> inappropriate time (thinking it's not being used anymore). But I'm
> expecting that PocoCapsule won't destroy the "fooPtr" bean while the
> "foo" bean that depends on it is in use.
>

You should:

1. define the foo bean as a non-singleton. this ensures its lifecycle
is inside its smart pointer wrapper's (i.e. the fooPtr's) lifecycle.
2. do not define the id for the Foo bean retrieved from the fooPtr
smart pointer (see my example above). This ensures this bean will not
be retrieved from the context and be used by users outside the
lifecycle of fooPtr bean.

> Since the new "foo" bean is a Foo* (the actual pointer, not a class),
> I can call Foo's methods on it, and deref it when passing to FooUser.
>
>
>
> > Supporting smart pointers as factory return values explicitly in
> > PocoCapsule should require minimum works. Basically the boilerplate
> > code of FooPtrFactory::create(...) in above example can be
> > automatically generated by pxgenproxy (this assumes the FooPtr defines
> > a copy ctor). This was considered during early design but was
> > eventually dropped due to the programming practice of CORBA world
> > where even smart pointers (i.e. _var classes) are widely used,
> > factories are commonly return raw pointers instead of smart pointers.
> > If factories returning smart pointers is a common programming
> > practice, I will reconsider to explicitly support it in a minor
> > release.
>
> I don't know how common the practice of returning smart pointers from
> factories might be. I certainly expect the use of smart pointers
> (especially Boost's) to grow in the future. Boost's smart pointer
> classes are part of the TR1 addition to the standard C++ library, and
> are advocated in _Effective_C++_ by Scott Meyers. Plus, it makes a
> lot of sense (to me anyway) to have factories return safer, wrapped
> pointers, instead of raw pointers that have to be manually wrapped by
> the receiver upon creation (which makes memory leaks more likely).
>

Many thanks for your information and comment!

> I hope that if you do decide to support this kind of factory in a
> future version of PocoCapsule, that you also arrange for the generated
> proxies to automatically dereference the pointer-to-shared-pointer
> back into a shared-pointer, so that the additional (and possibly
> dangerous) dereferencing step I showed above is not necessary.
>

Certainly. I will seriously consider your suggestions. Things I need
to consider is compromise the simplicity of core schema and the
consistency of the framework (for instance, lifecycle control roles,
AppContext::getBean() return values, etc.).

> Thanks again,
> -- Bryan Raney
>
> P.S. In case it helps you, I have learned that a boost::shared_ptr<T>
> can be converted to boost::shared_ptr<void>, to mimic the use of void*
> to store any type. (Seehttp://www.boost.org/doc/libs/1_37_0/libs/smart_ptr/sp_techniques.htm...
> for more info.)
>

Thanks! My consideration is to support arbitrary smart pointer (i.e.
boost's, CORBA C++, and various WSDL C++ mappings, etc.) and even
arbitrary return values rather than only the smart pointer of boost.
Besides, PocoCapsule supports the use of templates and boost
libraries. However, it deliberately avoids to explicitly use and/or
depend on them (and stl, exceptions, thread, RTTI etc. as well) for
the consideration of portability, runtime footprint, etc..

Thanks again for your feedback and great information!
Ke

Bryan Raney

unread,
Jan 29, 2009, 3:33:10 PM1/29/09
to pococ...@googlegroups.com
Hi Ke,

More inline responses below...

Your idea with using the "get()" method as a factory method does seem
a bit cleaner than my way.

From your comments below, I assume you intended to leave the id off
this bean. I have a question about that (below), so for clarity I
will still refer to this as the "foo" bean.

[snip]

> My suggested approach above allows you to pass the raw pointer
> (encapsulated inside the fooPtr smart pointer object) by reference as:
>
> <bean class="FooUser" ...>
> <method-arg ref="foo" pass="deref"/>
> </bean>

[snip my almost-identical version]

This bean seems to be referring to the "foo" bean (defined above) even
though the "foo" bean doesn't have an id. Will that still work?

> You should:
>
> 1. define the foo bean as a non-singleton. this ensures its lifecycle
> is inside its smart pointer wrapper's (i.e. the fooPtr's) lifecycle.
> 2. do not define the id for the Foo bean retrieved from the fooPtr
> smart pointer (see my example above). This ensures this bean will not
> be retrieved from the context and be used by users outside the
> lifecycle of fooPtr bean.

Thanks for the tips. I guess I'm still wrapping my head around the
best way to describe things to PocoCapsule.

Let me make sure I understand the lifecycle of the "foo" bean, based
on item (1) and the related information from the devleoper's guide:
* The "foo" bean gets created immediately before the FooUser bean is
created, since the FooUser bean needs the foo bean.
* The "foo" bean gets destroyed immediately after the FooUser bean's
constructor returns, since "foo" is not a singleton and has no more
reason to live.
* The "foo" bean gets destroyed before any more beans are created,
even if those beans rely on either "foo" (a different instance) or the
FooUser bean.

Is this correct?

For (2), that sounds like a good reason to leave off the id, but see
my question above regarding the FooUser bean and the Foo bean.

[snip some more]

>> I hope that if you do decide to support this kind of factory in a
>> future version of PocoCapsule, that you also arrange for the generated
>> proxies to automatically dereference the pointer-to-shared-pointer
>> back into a shared-pointer, so that the additional (and possibly
>> dangerous) dereferencing step I showed above is not necessary.
>>
>
> Certainly. I will seriously consider your suggestions. Things I need
> to consider is compromise the simplicity of core schema and the
> consistency of the framework (for instance, lifecycle control roles,
> AppContext::getBean() return values, etc.).

I certainly understand those considerations. I was already trying to
think about how the core schema could differentiate between regular
pointers and smart pointers in the "class" attribute of <bean>, but
didn't see an obvious solution.

>
>> Thanks again,
>> -- Bryan Raney
>>
>> P.S. In case it helps you, I have learned that a boost::shared_ptr<T>
>> can be converted to boost::shared_ptr<void>, to mimic the use of void*
>> to store any type. (Seehttp://www.boost.org/doc/libs/1_37_0/libs/smart_ptr/sp_techniques.htm...
>> for more info.)
>>
>
> Thanks! My consideration is to support arbitrary smart pointer (i.e.
> boost's, CORBA C++, and various WSDL C++ mappings, etc.) and even
> arbitrary return values rather than only the smart pointer of boost.
> Besides, PocoCapsule supports the use of templates and boost
> libraries. However, it deliberately avoids to explicitly use and/or
> depend on them (and stl, exceptions, thread, RTTI etc. as well) for
> the consideration of portability, runtime footprint, etc..

Of course I understand you would want to support all kinds of smart
pointers, not just those from Boost.

>
> Thanks again for your feedback and great information!
> Ke

You're very welcome. Thank you for your feedback and advice, as well.

-- Bryan Raney

Ke Jin

unread,
Jan 30, 2009, 1:05:35 PM1/30/09
to pococapsule
On Jan 29, 12:33 pm, Bryan Raney <bra...@gmail.com> wrote:
>
> From your comments below, I assume you intended to leave the id off
> this bean.  I have a question about that (below), so for clarity I
> will still refer to this as the "foo" bean.
>

Yes, you are correct!

>
> This bean seems to be referring to the "foo" bean (defined above) even
> though the "foo" bean doesn't have an id.  Will that still work?
>
> > You should:
>
> > 1. define the foo bean as a non-singleton. this ensures its lifecycle
> > is inside its smart pointer wrapper's (i.e. the fooPtr's) lifecycle.
> > 2. do not define the id for the Foo bean retrieved from the fooPtr
> > smart pointer (see my example above). This ensures this bean will not
> > be retrieved from the context and be used by users outside the
> > lifecycle of fooPtr bean.
>
> Thanks for the tips.  I guess I'm still wrapping my head around the
> best way to describe things to PocoCapsule.
>
> Let me make sure I understand the lifecycle of the "foo" bean, based
> on item (1) and the related information from the devleoper's guide:
>   * The "foo" bean gets created immediately before the FooUser bean is
> created, since the FooUser bean needs the foo bean.
>   * The "foo" bean gets destroyed immediately after the FooUser bean's
> constructor returns, since "foo" is not a singleton and has no more
> reason to live.

Yes, a non-singleton bean will be recreated (calling its constructor
or factory-method) each time before it is used (as a factory bean or
method-arg) and then released (calling its destroy-method) immediately
after this use (see lifecycle control section in Dev Guide).

>   * The "foo" bean gets destroyed before any more beans are created,
> even if those beans rely on either "foo" (a different instance) or the
> FooUser bean.
>
> Is this correct?
>

No. The foo bean, as a non-singleton, actually will not even be
created before it is used. It will be create/recreated every time on-
use and immediately deleted after use. The singleton and non-singleton
in IoC container is different from the "singleton" in the design
pattern. In IoC container, singleton should be understood as a global
bean while a non-singleton bean is more like a bean on stack.

> For (2), that sounds like a good reason to leave off the id, but see
> my question above regarding the FooUser bean and the Foo bean.
>

Yes, you are right. Although we don't want this on stack bean to be
retrieved by AppContext::getBean(), we would have to keep its id for
the purpose to be referenced in other bean definitions.

> [snip some more]
>
>
> I certainly understand those considerations. I was already trying to
> think about how the core schema could differentiate between regular
> pointers and smart pointers in the "class" attribute of <bean>, but
> didn't see an obvious solution.
>

This is what I think: introduce an optional attribute 'factory-return'
for <bean> element. This attribute could take the following values:

1. "by-ptr" (default, any non-constant pointer),
2. "by-smart-ptr" (smart pointer and support assignment operator, to
be used by calling -> on the value),
3. "by-wrapped-ptr" (smart pointer and support copy ctor, to be used
by calling -> on the value),
4. "by-value" (any return by value support assignment operator, but
not going to be used by calling -> on the value),
5. "by-copy" (any return by value support copy ctor, but not going to
be used by calling -> on the value),
6. "by-ref" (by non-constant reference),
etc.

For "by-smart-ptr" and "by-wapped-ptr", the engine will:
1. call "->" on the smart pointer value (rather than on the pointer
points to the value) (this avoids the double deref you pointed out in
previous email).
2. always pass the smart pointer by value or reference (i.e. ignore
the 'pass' attribute).
3. delete-method is "delete" regardless user setting (i.e. ignore the
'destroy-method' attribute).
4. getBean() returns a pointer pointing to the smart pointer rather
than the smart pointer value itself.

This enhancement is trivial and should be piggybacked in next minor
release. That release is to support gSoap by another user's
requirement. It still needs several weeks to complete.

Comments and suggestions?

Thanks!
Ke

Bryan Raney

unread,
Feb 2, 2009, 7:43:29 PM2/2/09
to pococ...@googlegroups.com
Hi Ke,

Please see my inline comments.

On Fri, Jan 30, 2009 at 12:05 PM, Ke Jin <kji...@gmail.com> wrote:
> On Jan 29, 12:33 pm, Bryan Raney <bra...@gmail.com> wrote:
>> Let me make sure I understand the lifecycle of the "foo" bean, based
>> on item (1) and the related information from the devleoper's guide:
>> * The "foo" bean gets created immediately before the FooUser bean is
>> created, since the FooUser bean needs the foo bean.
>> * The "foo" bean gets destroyed immediately after the FooUser bean's
>> constructor returns, since "foo" is not a singleton and has no more
>> reason to live.
>
> Yes, a non-singleton bean will be recreated (calling its constructor
> or factory-method) each time before it is used (as a factory bean or
> method-arg) and then released (calling its destroy-method) immediately
> after this use (see lifecycle control section in Dev Guide).
>
>> * The "foo" bean gets destroyed before any more beans are created,
>> even if those beans rely on either "foo" (a different instance) or the
>> FooUser bean.
>>
>> Is this correct?
>>
>
> No. The foo bean, as a non-singleton, actually will not even be
> created before it is used. It will be create/recreated every time on-
> use and immediately deleted after use. The singleton and non-singleton
> in IoC container is different from the "singleton" in the design
> pattern. In IoC container, singleton should be understood as a global
> bean while a non-singleton bean is more like a bean on stack.

I have a feeling we are agreeing, but saying things differently enough
so as to not notice. :-) I was asking if the (non-singleton) "foo"
bean gets destroyed after every use, even if it (the "foo" bean
concept described in setup.xml) is going to be used again by another
bean. Though you said no, you also said it (the "foo" bean) will be
recreated every time on-use. That sounds like you were really saying
yes to my question. Is there some subtle discrepancy I'm not
noticing?

I realize that it's not going to be the same *instance* each time its
used, since it's a non-singleton.

>
>> For (2), that sounds like a good reason to leave off the id, but see
>> my question above regarding the FooUser bean and the Foo bean.
>>
>
> Yes, you are right. Although we don't want this on stack bean to be
> retrieved by AppContext::getBean(), we would have to keep its id for
> the purpose to be referenced in other bean definitions.

OK, that helps me be more clear about all of this.

>> [snip some more]
>>
>> I certainly understand those considerations. I was already trying to
>> think about how the core schema could differentiate between regular
>> pointers and smart pointers in the "class" attribute of <bean>, but
>> didn't see an obvious solution.
>>
>
> This is what I think: introduce an optional attribute 'factory-return'
> for <bean> element. This attribute could take the following values:
>
> 1. "by-ptr" (default, any non-constant pointer),
> 2. "by-smart-ptr" (smart pointer and support assignment operator, to
> be used by calling -> on the value),
> 3. "by-wrapped-ptr" (smart pointer and support copy ctor, to be used
> by calling -> on the value),
> 4. "by-value" (any return by value support assignment operator, but
> not going to be used by calling -> on the value),
> 5. "by-copy" (any return by value support copy ctor, but not going to
> be used by calling -> on the value),
> 6. "by-ref" (by non-constant reference),
> etc.

OK, I like that. These options make it possible for the factory
method to have any return type, instead of just a pointer.

I'm not sure I understand the differentiation between #2 & #3, and #4
and #5. Does it change the way the factory method is used?

>
> For "by-smart-ptr" and "by-wapped-ptr", the engine will:
> 1. call "->" on the smart pointer value (rather than on the pointer
> points to the value) (this avoids the double deref you pointed out in
> previous email).
> 2. always pass the smart pointer by value or reference (i.e. ignore
> the 'pass' attribute).

I'm not sure if #2 will work in all cases. Sometimes I still want to
dereference the smart pointer. If my receiving method has a signature
like this:

void myFun( Blah& myBlah );

And I have an object "blahPtr", which is of type
"boost::shared_ptr<Blah>", I will want to call myFun like this:

myFun( *blahPtr );

But what you are saying sounds like my only choices are:
1) call myFun( blahPtr ); // no star
2) use the "blahPtr.get()" in an intermediate factory method (as in
the previous postings) to disconnect the smart pointer from the call
to myFun

So I think the "pass" attribute might still be useful, to allow:
3) <ioc method="myFun" target="none">
<method-arg type="bean" ref="blahPtr" pass="deref" />
</ioc>

which becomes

myFun( *blahPtr );

(Please correct me if I'm wrong.)

> 3. delete-method is "delete" regardless user setting (i.e. ignore the
> 'destroy-method' attribute).

I don't have a specific problem with this, but it does seem to
contradict what the developer's guide says about the destroy method,
namely "a destroy-method can serve as the last cleanup procedure to
unsubscribe the bean from a publish/subscribe event service or
deregister the bean from an external directory service". Wouldn't
ignoring the destroy method prevent this functionality?

> 4. getBean() returns a pointer pointing to the smart pointer rather
> than the smart pointer value itself.
>
> This enhancement is trivial and should be piggybacked in next minor
> release. That release is to support gSoap by another user's
> requirement. It still needs several weeks to complete.
>
> Comments and suggestions?

>
> Thanks!
> Ke

Thanks for listening to your users,

-- Bryan Raney

Ke Jin

unread,
Feb 2, 2009, 11:04:40 PM2/2/09
to pococapsule
Bryan,

See inline responses.

Ke

On Feb 2, 4:43 pm, Bryan Raney <bra...@gmail.com> wrote:
>
> I have a feeling we are agreeing, but saying things differently enough
> so as to not notice. :-) I was asking if the (non-singleton) "foo"
> bean gets destroyed after every use, even if it (the "foo" bean
> concept described in setup.xml) is going to be used again by another
> bean. Though you said no, you also said it (the "foo" bean) will be
> recreated every time on-use. That sounds like you were really saying
> yes to my question. Is there some subtle discrepancy I'm not
> noticing?
>
> I realize that it's not going to be the same *instance* each time its
> used, since it's a non-singleton.
>

Yes, you are correct.

>
> > This is what I think: introduce an optional attribute 'factory-return'
> > for <bean> element. This attribute could take the following values:
>
> > 1. "by-ptr" (default, any non-constant pointer),
> > 2. "by-smart-ptr" (smart pointer and support assignment operator, to
> > be used by calling -> on the value),
> > 3. "by-wrapped-ptr" (smart pointer and support copy ctor, to be used
> > by calling -> on the value),
> > 4. "by-value" (any return by value support assignment operator, but
> > not going to be used by calling -> on the value),
> > 5. "by-copy" (any return by value support copy ctor, but not going to
> > be used by calling -> on the value),
> > 6. "by-ref" (by non-constant reference),
> > etc.
>
> OK, I like that. These options make it possible for the factory
> method to have any return type, instead of just a pointer.
>
> I'm not sure I understand the differentiation between #2 & #3, and #4
> and #5. Does it change the way the factory method is used?
>

With #2 and #4, the assignment operator (i.e. = operator) will be used
to save the returned value. With #3 and #5, the copy ctor will be
used. Some value or pointer wrapper definitions only define one of
these two methods not both of them. For boost smart pointers, either
one will be fine.

>
> > For "by-smart-ptr" and "by-wapped-ptr", the engine will:
> > 1. call "->" on the smart pointer value (rather than on the pointer
> > points to the value) (this avoids the double deref you pointed out in
> > previous email).
> > 2. always pass the smart pointer by value or reference (i.e. ignore
> > the 'pass' attribute).
>
> I'm not sure if #2 will work in all cases. Sometimes I still want to
> dereference the smart pointer. If my receiving method has a signature
> like this:
>

No. What I said is the smart (and wrapper, value, copy objects) are
always passed by references and not by pointers.

> void myFun( Blah& myBlah );
>
> And I have an object "blahPtr", which is of type
> "boost::shared_ptr<Blah>", I will want to call myFun like this:
>
> myFun( *blahPtr );
>

I guess you mean:

boost::shared_ptr<Blah> blahPtr = ...;

Here, the blahPtr is a smart pointer object, rather than a pointer.
So, we don't need to dereference it when pass it by reference.
It will simply be passed as:

myFun(blahPtr); // i.e. by reference.

> But what you are saying sounds like my only choices are:
> 1) call myFun( blahPtr ); // no star

Yes

> 2) use the "blahPtr.get()" in an intermediate factory method (as in
> the previous postings) to disconnect the smart pointer from the call
> to myFun
>

No. The blahPtr.get() return a raw pointer. It can't be passed to the
myFun() explicitly.

> So I think the "pass" attribute might still be useful, to allow:
> 3) <ioc method="myFun" target="none">
> <method-arg type="bean" ref="blahPtr" pass="deref" />
> </ioc>
>
> which becomes
>
> myFun( *blahPtr );
>

What the "*" operator does here?

> (Please correct me if I'm wrong.)
>
> > 3. delete-method is "delete" regardless user setting (i.e. ignore the
> > 'destroy-method' attribute).
>
> I don't have a specific problem with this, but it does seem to
> contradict what the developer's guide says about the destroy method,
> namely "a destroy-method can serve as the last cleanup procedure to
> unsubscribe the bean from a publish/subscribe event service or
> deregister the bean from an external directory service". Wouldn't
> ignoring the destroy method prevent this functionality?
>

the destroy-method for smart-pointer (and wrapper pointer, value,
copy) only delete their holder objects which are allocated by the
container (in the generated code) rather than the actual raw pointer
stored in these holder objects as if they were go out of scope. The
destructor of these holder objects should perform the actual destroy
clean up (such as unregister subscribers etc..). That is actually the
point of using these smart/wrappered pointers, i.e. to hide the detail
destroy method from users. Users only need to ensure these holder
objects are "deleted" when go out of their definition scopes (the
simplest way is put them on stack).

>
> Thanks for listening to your users,
>

You are very welcome!

Ke

Bryan Raney

unread,
Feb 3, 2009, 11:34:55 AM2/3/09
to pococ...@googlegroups.com
Hi Ke,

On Mon, Feb 2, 2009 at 10:04 PM, Ke Jin <kji...@gmail.com> wrote:
> On Feb 2, 4:43 pm, Bryan Raney <bra...@gmail.com> wrote:
>>
>> > This is what I think: introduce an optional attribute 'factory-return'
>> > for <bean> element. This attribute could take the following values:
>>
>> > 1. "by-ptr" (default, any non-constant pointer),
>> > 2. "by-smart-ptr" (smart pointer and support assignment operator, to
>> > be used by calling -> on the value),
>> > 3. "by-wrapped-ptr" (smart pointer and support copy ctor, to be used
>> > by calling -> on the value),
>> > 4. "by-value" (any return by value support assignment operator, but
>> > not going to be used by calling -> on the value),
>> > 5. "by-copy" (any return by value support copy ctor, but not going to
>> > be used by calling -> on the value),
>> > 6. "by-ref" (by non-constant reference),
>> > etc.
>>
>> OK, I like that. These options make it possible for the factory
>> method to have any return type, instead of just a pointer.
>>
>> I'm not sure I understand the differentiation between #2 & #3, and #4
>> and #5. Does it change the way the factory method is used?
>>
>
> With #2 and #4, the assignment operator (i.e. = operator) will be used
> to save the returned value. With #3 and #5, the copy ctor will be
> used. Some value or pointer wrapper definitions only define one of
> these two methods not both of them. For boost smart pointers, either
> one will be fine.

OK, thanks, I understand now. Each option in the list would generate
slightly different code inside the proxy, so must be differentiated.

>> > For "by-smart-ptr" and "by-wapped-ptr", the engine will:
>> > 1. call "->" on the smart pointer value (rather than on the pointer
>> > points to the value) (this avoids the double deref you pointed out in
>> > previous email).
>> > 2. always pass the smart pointer by value or reference (i.e. ignore
>> > the 'pass' attribute).
>>
>> I'm not sure if #2 will work in all cases. Sometimes I still want to
>> dereference the smart pointer. If my receiving method has a signature
>> like this:
>>
>
> No. What I said is the smart (and wrapper, value, copy objects) are
> always passed by references and not by pointers.
>
>> void myFun( Blah& myBlah );

Notice, this takes a Blah object by reference, NOT a boost::shared_ptr<Blah>.

>>
>> And I have an object "blahPtr", which is of type
>> "boost::shared_ptr<Blah>", I will want to call myFun like this:
>>
>> myFun( *blahPtr );
>>
>
> I guess you mean:
>
> boost::shared_ptr<Blah> blahPtr = ...;

Yes, that is what I meant.

> Here, the blahPtr is a smart pointer object, rather than a pointer.
> So, we don't need to dereference it when pass it by reference.
> It will simply be passed as:
>
> myFun(blahPtr); // i.e. by reference.

Except myFun doesn't take a smart pointer, it takes a Blah&. We must
use the * operator (see below) to turn the smart pointer into a Blah&.

>> But what you are saying sounds like my only choices are:
>> 1) call myFun( blahPtr ); // no star
>
> Yes

But this would not compile, given the definition of myFun and blahPtr
mentioned above, since myFun takes Blah by reference, not by pointer,
or by smart-pointer even. myFun() has no idea about the
boost::smart_ptr that's being used outside of it's scope.

>> 2) use the "blahPtr.get()" in an intermediate factory method (as in
>> the previous postings) to disconnect the smart pointer from the call
>> to myFun
>>
>
> No. The blahPtr.get() return a raw pointer. It can't be passed to the
> myFun() explicitly.

I know, I just meant that if the "pass" attribute is ignored for smart
pointers, I'd have to get the raw pointer first (like in the example
from our earlier emails with the factory that returned
smart_ptr<Foo>), so I can use the pass="deref" option __on that raw
pointer__ to give myFun a Blah& instead of a Blah* or
boost::shared_ptr<Blah>. As was shown in the earlier example, this
will work, but it is less convenient.

>> So I think the "pass" attribute might still be useful, to allow:
>> 3) <ioc method="myFun" target="none">
>> <method-arg type="bean" ref="blahPtr" pass="deref" />
>> </ioc>
>>
>> which becomes
>>
>> myFun( *blahPtr );
>>
>
> What the "*" operator does here?

For boost::shared_ptr<Blah>, the operator* returns a Blah&. So, the
line of code in question acts (almost) like it would if blahPtr was a
raw Blah* pointer -- i.e., it deferences the pointer (held inside the
smart pointer object) to get back an actual object (or at least an
object reference), which is passed to myFun.

Hopefully this example shows how the "pass" attribute is still useful
for smart pointers.

>> > 3. delete-method is "delete" regardless user setting (i.e. ignore the
>> > 'destroy-method' attribute).
>>
>> I don't have a specific problem with this, but it does seem to
>> contradict what the developer's guide says about the destroy method,
>> namely "a destroy-method can serve as the last cleanup procedure to
>> unsubscribe the bean from a publish/subscribe event service or
>> deregister the bean from an external directory service". Wouldn't
>> ignoring the destroy method prevent this functionality?
>>
>
> the destroy-method for smart-pointer (and wrapper pointer, value,
> copy) only delete their holder objects which are allocated by the
> container (in the generated code) rather than the actual raw pointer
> stored in these holder objects as if they were go out of scope. The
> destructor of these holder objects should perform the actual destroy
> clean up (such as unregister subscribers etc..). That is actually the
> point of using these smart/wrappered pointers, i.e. to hide the detail
> destroy method from users. Users only need to ensure these holder
> objects are "deleted" when go out of their definition scopes (the
> simplest way is put them on stack).

Yes, I agree that's how such holder objects work. I think what you're
saying is that if I need to associate a specific destroy method with
the object held by my smart pointer, I should use the smart-pointer's
mechanism for that, which lies outside of PocoCapsule anyway. OK, no
problem.

That's all I have for now.

Thanks again,
-- Bryan

Ke Jin

unread,
Feb 3, 2009, 7:31:14 PM2/3/09
to pococapsule
Now I see what you mean. See inline ...

Ke

On Feb 3, 8:34 am, Bryan Raney <bra...@gmail.com> wrote:
> Hi Ke,
>
>
> >>    void myFun( Blah& myBlah );
>
> Notice, this takes a Blah object by reference, NOT a boost::shared_ptr<Blah>.
>

Yes, I see this now. Sorry for the confusion.

>
>
> >> And I have an object "blahPtr", which is of type
> >> "boost::shared_ptr<Blah>", I will want to call myFun like this:
>
> >>   myFun( *blahPtr );
>
> > I guess you mean:
>
> > boost::shared_ptr<Blah> blahPtr = ...;
>
> Yes, that is what I meant.
>
> > Here, the blahPtr is a smart pointer object, rather than a pointer.
> > So, we don't need to dereference it when pass it by reference.
> > It will simply be passed as:
>
> > myFun(blahPtr); // i.e. by reference.
>
> Except myFun doesn't take a smart pointer, it takes a Blah&.  We must
> use the * operator (see below) to turn the smart pointer into a Blah&.
>
> >> But what you are saying sounds like my only choices are:
> >>   1)  call myFun( blahPtr ); // no star
>
> > Yes
>
> But this would not compile, given the definition of myFun and blahPtr
> mentioned above, since myFun takes Blah by reference, not by pointer,
> or by smart-pointer even.  myFun() has no idea about the
> boost::smart_ptr that's being used outside of it's scope.
>

Yes, you are right. I thought you were asking to pass the smart
pointer object by reference and didn't notice the function is actually
defined as passing the dereferenced stored pointer by reference.

>
> I know, I just meant that if the "pass" attribute is ignored for smart
> pointers, I'd have to get the raw pointer first (like in the example
> from our earlier emails with the factory that returned
> smart_ptr<Foo>), so I can use the pass="deref" option __on that raw
> pointer__ to give myFun a Blah& instead of a Blah* or
> boost::shared_ptr<Blah>.  As was shown in the earlier example, this
> will work, but it is less convenient.
>

The problem of passing the dereferenced stored pointer by reference
is:

1. it is not a common practice to define such a "*" operator for smart
pointers. For instance, OMG's smart pointers do not define such
operator.
2. most value objects do not define such operator.

If this was supported using the "pass" attribute, then the "pass"
attribute would have to have a special behavior/rule for boost smart
pointer different from the behavior/rule for for other smart pointers,
wrapper pointers, values and copies. That would be too complicated and
confused for users. So, I feel let users to retrieve the stored
pointers and then use the "pass" attribute in this case will have the
rule much simple, clear, and consistent.

Again, many thanks again for your valuable suggestions,

Ke

Bryan Raney

unread,
Feb 5, 2009, 5:18:01 PM2/5/09
to pococ...@googlegroups.com
Hi Ke,

On Tue, Feb 3, 2009 at 6:31 PM, Ke Jin <kji...@gmail.com> wrote:
>
> Now I see what you mean. See inline ...

I'm glad it's cleared up!

> On Feb 3, 8:34 am, Bryan Raney <bra...@gmail.com> wrote:
>> >> And I have an object "blahPtr", which is of type
>> >> "boost::shared_ptr<Blah>", I will want to call myFun like this:
>>
>> >> myFun( *blahPtr );
>>

>> > Here, the blahPtr is a smart pointer object, rather than a pointer.
>> > So, we don't need to dereference it when pass it by reference.
>> > It will simply be passed as:
>>
>> > myFun(blahPtr); // i.e. by reference.
>>
>> Except myFun doesn't take a smart pointer, it takes a Blah&. We must
>> use the * operator (see below) to turn the smart pointer into a Blah&.
>>
>> >> But what you are saying sounds like my only choices are:
>> >> 1) call myFun( blahPtr ); // no star
>>
>> > Yes
>>
>> But this would not compile, given the definition of myFun and blahPtr
>> mentioned above, since myFun takes Blah by reference, not by pointer,
>> or by smart-pointer even. myFun() has no idea about the
>> boost::smart_ptr that's being used outside of it's scope.
>>
>
> Yes, you are right. I thought you were asking to pass the smart
> pointer object by reference and didn't notice the function is actually
> defined as passing the dereferenced stored pointer by reference.

OK, now we're on the same page. :)

>> I know, I just meant that if the "pass" attribute is ignored for smart
>> pointers, I'd have to get the raw pointer first (like in the example
>> from our earlier emails with the factory that returned
>> smart_ptr<Foo>), so I can use the pass="deref" option __on that raw
>> pointer__ to give myFun a Blah& instead of a Blah* or
>> boost::shared_ptr<Blah>. As was shown in the earlier example, this
>> will work, but it is less convenient.
>>
>
> The problem of passing the dereferenced stored pointer by reference
> is:
>
> 1. it is not a common practice to define such a "*" operator for smart
> pointers. For instance, OMG's smart pointers do not define such
> operator.
> 2. most value objects do not define such operator.
>
> If this was supported using the "pass" attribute, then the "pass"
> attribute would have to have a special behavior/rule for boost smart
> pointer different from the behavior/rule for for other smart pointers,
> wrapper pointers, values and copies. That would be too complicated and
> confused for users. So, I feel let users to retrieve the stored
> pointers and then use the "pass" attribute in this case will have the
> rule much simple, clear, and consistent.

I haven't looked very closely at the code that generates the C++
proxies, but my impression is that setting pass="deref" inside a
<method-arg> tag basically had the effect of pre-pending the "*"
character to the appropriate argument when passed to the appropriate
method. I don't see how this would change for a smart pointer or
other pass-by-value situations. In fact, I don't understand why a
special rule would be necessary at all (adding a star is adding a
star!). Here I'm talking about the pass attribute only -- I know
smart pointers in general will require other processing, but it seems
like that would have been completed by the time the pass attribute it
looked at. But as I said, that's only my guess as to how it would
work.

Certainly, it's your library, and you can add or not add whatever you
want. The other changes / features you've discussed will still be
useful with factories that return smart pointers.

>
> Again, many thanks again for your valuable suggestions,
>
> Ke

You're welcome. I'm happy to participate.

Thanks again for all of your attention to this topic.

-- Bryan Raney

Ke Jin

unread,
Feb 5, 2009, 11:08:43 PM2/5/09
to pococapsule
Bryan,

Thanks again! see inline ....

On Feb 5, 2:18 pm, Bryan Raney <bra...@gmail.com> wrote:
>
> I haven't looked very closely at the code that generates the C++
> proxies, but my impression is that setting pass="deref" inside a
> <method-arg> tag basically had the effect of pre-pending the "*"
> character to the appropriate argument when passed to the appropriate
> method.  

Yes, you are correct!

> I don't see how this would change for a smart pointer or
> other pass-by-value situations.  

Here we are talking about applying the "*" on a smart pointer object.
This is different from applying the operator on a pointer pointing to
the smart pointer object or on a raw pointer. Therefore, this assumes
the "*" operator is defined on the smart pointer class which is not
necessary true.

> In fact, I don't understand why a
> special rule would be necessary at all (adding a star is adding a
> star!).  

First, for a raw pointer, the "*" operator is always valid, therefore
pass="deref" will always work if the invoked ioc method is defined to
pass that argument by value or reference. For smart-pointer/wrapped-
pointer/value/copy etc., the "*" operator is likely not defined. If we
defined the pass="deref" to be passing the stored raw object by value/
reference, then it would not work in many smart-pointer/wrapper-
pointer/value/copy cases even if the invoked ioc function itself was
defined as passing the raw stored object by reference or value. This
problem would only be reported by C++ compiler on building the
generated proxy. This would require users to really look into the code
and figure out how "deref" a smart/wrapped pointer was interpreted by
PocoCapsule proxies.

Secondly, using the "*" operator to extract the stored object and pass
it by reference/value assumes that the user get a smart/wrapped
pointer return by value from a factory and then attempt to pass the
raw object in calling ioc method instead. My feeling is (I could be
very wrong), most users would not mix use smart-pointer/wrapped-
pointer with raw pointers or values. Namely, if they use factories
return raw pointers, they will likely also pass these raw pointers by
pointer or by dereferenced objects rather than by smart-pointers/
wrapped-pointers. Smart-pointers are used to hold these raw pointers
for automatic releasing when their holders go out of scope. This is
how most CORBA applications use smart pointers. If users use factories
that return smart or wrapped pointers by values, then, they would
likely to pass these smart/wrapped pointers by value/references as
well, instead of pass their stored pointers or stored objects. This is
how many HP sysinet's WS for C++ applications use smart pointers.

That said, I am still open to your suggestions on this issue but just
need time to balance.

Many thanks again!
Ke

Bryan Raney

unread,
Feb 12, 2009, 1:01:44 AM2/12/09
to pococ...@googlegroups.com
Hi Ke,

Sorry for the slow response. Please see inlined comments.

On Thu, Feb 5, 2009 at 10:08 PM, Ke Jin <kji...@gmail.com> wrote:
> On Feb 5, 2:18 pm, Bryan Raney <bra...@gmail.com> wrote:

>> I don't see how [pre-prending "*" when pass="deref"] would change for a smart pointer or


>> other pass-by-value situations.
>
> Here we are talking about applying the "*" on a smart pointer object.
> This is different from applying the operator on a pointer pointing to
> the smart pointer object or on a raw pointer. Therefore, this assumes
> the "*" operator is defined on the smart pointer class which is not
> necessary true.
>
>> In fact, I don't understand why a
>> special rule would be necessary at all (adding a star is adding a
>> star!).
>
> First, for a raw pointer, the "*" operator is always valid, therefore
> pass="deref" will always work if the invoked ioc method is defined to
> pass that argument by value or reference. For smart-pointer/wrapped-
> pointer/value/copy etc., the "*" operator is likely not defined. If we
> defined the pass="deref" to be passing the stored raw object by value/
> reference, then it would not work in many smart-pointer/wrapper-
> pointer/value/copy cases even if the invoked ioc function itself was
> defined as passing the raw stored object by reference or value. This
> problem would only be reported by C++ compiler on building the
> generated proxy. This would require users to really look into the code
> and figure out how "deref" a smart/wrapped pointer was interpreted by
> PocoCapsule proxies.

OK, I agree with you that using the "*" operator on a non-pointer type
may not always work. I see no reason to expect PocoCapsule to know
when "*" works and when it doesn't for non-pointer types.

I guess you're saying that since PocoCapsule cannot know for a
non-pointer type if "*" will work, then it should not allow the "*" to
be applied for such types. (Based on what you said above, and in a
previous email about ignoring the "pass" attribute.) I can somewhat
understand that since you expect "*" on non-pointer types to be wrong
more often than it is right.

My humble opinion is that since sometimes the "*" __is still valid__
PocoCapsule can allow it. It will work if the operator is defined for
the type, and it won't work otherwise. In cases where the operator is
not defined, I (as the author of the setup.xml) should not choose
pass="deref". This seems similar in my mind to the situation where I
am describing the arguments to a function call in setup.xml, and get
the order of arguments wrong, or use the wrong type for a particular
argument. PocoCapsule can't catch that mistake; it generates the
proxy code as instructed, then I discover the problem when the
compiler complains about the generated proxy code. It sounds like you
want to avoid having the compiler complain about the proxy code for
invalid use of "*", but there are other situations in which the
compiler will complain, so I don't see much of a distinction.

Anyway, I think I have a better understanding now of why you were
thinking of ignoring the pass attribute when passing beans that are
not true pointer types.

> Secondly, using the "*" operator to extract the stored object and pass
> it by reference/value assumes that the user get a smart/wrapped
> pointer return by value from a factory and then attempt to pass the
> raw object in calling ioc method instead. My feeling is (I could be
> very wrong), most users would not mix use smart-pointer/wrapped-
> pointer with raw pointers or values. Namely, if they use factories
> return raw pointers, they will likely also pass these raw pointers by
> pointer or by dereferenced objects rather than by smart-pointers/
> wrapped-pointers. Smart-pointers are used to hold these raw pointers
> for automatic releasing when their holders go out of scope. This is
> how most CORBA applications use smart pointers. If users use factories
> that return smart or wrapped pointers by values, then, they would
> likely to pass these smart/wrapped pointers by value/references as
> well, instead of pass their stored pointers or stored objects. This is
> how many HP sysinet's WS for C++ applications use smart pointers.

It may very well be the case that the situation I described -- i.e.,
obtaining objects by smart pointer from a factory, then passing them
by object-reference -- is unlikely and not common practice. I haven't
really seen "real life" code before that uses smart pointers, so I'm
figuring things out as I go.

>
> That said, I am still open to your suggestions on this issue but just
> need time to balance.

Certainly, I understand that writing a library means balancing the
needs of many users and many situations.

BTW, I'm not trying to argue for a feature that I really need. Mostly
I'm just trying to understand how your current and planned features
will work together, and trying to relate it all to the code that I'm
working on.

>
> Many thanks again!
> Ke

Likewise! I've enjoyed the discussion.

-- Bryan

Ke Jin

unread,
Feb 13, 2009, 2:39:42 AM2/13/09
to pococapsule
Bryan,

Thanks again. see inline comments.

Ke
I understand your point. Namely, the "deref" mode could be an option
anyway. If a particular smart pointer definition doesn't support the
"*" operator, users could simply not use this mode anyway. Yes, this
is true. However the problem is consistency. PocoCapsule supports
three kind of pass modes, namely "ptr", "deref", and "dup". The "dup"
is not relevant to this discussion and we could ignore it. Now look at
rules for "ptr" and "deref":

Rule A. For ordinary pointer types:
----------------------------------------------
* pass="ptr": pass the object by pointer
* pass="deref": deref the pointer (using the "*" op) and then pass the
result (by value or ref).

Rule B. For smart-pointer/wrapped-pointer/value/copy objects:
-------------------------------------------------------------------------------------
design 1:
* always (ignore the pass attribute): pass the object itself (by value
or ref).

design 2 (as you suggested):
* pass="ptr": pass the object (by value or ref)
* pass="deref": applying the "*" op (if it is supported) on the object
and then pass the result.

design 2:
* pass="obj": pass the object (by value or ref)
* pass="deref-obj": applying the "*" op (if it is supported) on the
object and then pass the result.

My feeling is that the design 2 would be too easy to be misreaded by
users. The XML code based on the design 2 would also be too easy to
confuse users. It is too easy for users to think that "ptr" and
"deref" in rule b would be similar to rule A, namely to mean passing
the pointer of the object (i.e. the smart-pointer etc.) and
dereference on the pointer pointing to the object respectively. Hence,
to avoid the potential misread and confusions between on rule B,
either we simply tell users to ignore the pass attribute in these
cases or, as design 3, we introduce new modes for the 'pass' attribute
make it distinct from rule A.
I certainly understand. This is a very fruitful discussion. I very
appreciate and open to your input (and will carefully consider them).
Please, please feel free to do so. Truly, thanks!

Ke

Bryan Raney

unread,
Feb 19, 2009, 4:15:08 PM2/19/09
to pococ...@googlegroups.com
Hi Ke,

Now I see what I was missing before. See inline...

I understand now what you've been saying about special rules. When I
wrote earlier about pass="deref", I wasn't thinking about what it
means when pass="ptr"!

> Rule A. For ordinary pointer types:
> ----------------------------------------------
> * pass="ptr": pass the object by pointer
> * pass="deref": deref the pointer (using the "*" op) and then pass the
> result (by value or ref).
>
> Rule B. For smart-pointer/wrapped-pointer/value/copy objects:
> -------------------------------------------------------------------------------------
> design 1:
> * always (ignore the pass attribute): pass the object itself (by value
> or ref).
>
> design 2 (as you suggested):
> * pass="ptr": pass the object (by value or ref)
> * pass="deref": applying the "*" op (if it is supported) on the object
> and then pass the result.
>
> design 2:

For clarity, I'm assuming this is "design 3":

> * pass="obj": pass the object (by value or ref)
> * pass="deref-obj": applying the "*" op (if it is supported) on the
> object and then pass the result.
>
> My feeling is that the design 2 would be too easy to be misreaded by
> users. The XML code based on the design 2 would also be too easy to
> confuse users. It is too easy for users to think that "ptr" and
> "deref" in rule b would be similar to rule A, namely to mean passing
> the pointer of the object (i.e. the smart-pointer etc.) and
> dereference on the pointer pointing to the object respectively. Hence,
> to avoid the potential misread and confusions between on rule B,
> either we simply tell users to ignore the pass attribute in these
> cases or, as design 3, we introduce new modes for the 'pass' attribute
> make it distinct from rule A.

I agree that design 2 (Rule B) is misleading. Setting pass="ptr" for
smart pointers can be ambiguous. And "ptr" as its defined doesn't
make much sense for beans that are values and not any kind of pointer.

Comparing designs 2 and 3 (you of course may still choose design 1, in
which case it doesn't matter), having a new "obj" value for the pass
attribute makes sense, especially to use instead of "ptr" for non
pointer-types. However, I'm not sure I see the difference from a
user's point of view between "deref" from Rule A and "deref-obj" from
Rule B. They both mean "put a * in front", right? I realize that for
non-pointer types your proxy code will have an implicit extra step of
dereferencing a pointer to the bean before adding the requested "*";
but it seems this is an implementation detail more than something the
user should have to worry about.

Also, pass="ptr" in Rule A, and pass="obj" in Rule B are conceptually
different in terms of what kinds of beans they apply to, but really
they both tell PocoCapsule to do the same thing, right? That is,
don't they both say "just pass the bean as-is; do not change it"?
(For non-pointer beans, there is an extra dereference step, but again
I don't see the need to expose this too much.) If that is the case, I
wonder if instead of adding a new value for the pass attribute
("obj"), if it would make sense to change "ptr" to something more
generic, like "as-is". Then you'd have:

Rule A. For ordinary pointer types:

--------------------------------------------------
* pass="as-is": pass the object (by pointer because Rule A is for
ordinary pointers)
* pass="deref": apply the "*" operator (supported by ordinary
pointers) on the object and then pass the result

Rule B. For smart-pointer/wrapped-pointer/value/copy objects:

-----------------------------------------------------------------------------------------
* pass="as-is": pass the object (by value/ref because Rule B is for
things that aren't ordinary pointers)
* pass="deref": apply the "*" operator (if it is supported) on the


object and then pass the result

(not sure if this affects "dup" or not)

Which would mean it doesn't matter to the user what kind of bean
something is (pointer, smart pointer, value, etc.) -- all beans are
treated the same. Just a thought.

>> > That said, I am still open to your suggestions on this issue but just
>> > need time to balance.
>>
>> Certainly, I understand that writing a library means balancing the
>> needs of many users and many situations.
>>
>> BTW, I'm not trying to argue for a feature that I really need. Mostly
>> I'm just trying to understand how your current and planned features
>> will work together, and trying to relate it all to the code that I'm
>> working on.
>>
>
> I certainly understand. This is a very fruitful discussion. I very
> appreciate and open to your input (and will carefully consider them).
> Please, please feel free to do so. Truly, thanks!
>
> Ke

You're welcome, and I'm happy to hear it!
-- Bryan

Ke Jin

unread,
Feb 21, 2009, 3:28:25 PM2/21/09
to pococapsule
Bryan,

Thanks for the suggestion. Yes, I am also thinking alone the same line
(and trying to find a word better than "as-is" :)).

Thanks again!
Ke
Reply all
Reply to author
Forward
0 new messages