Archived

This forum has been archived. Please start a new discussion on GitHub.

The most natural way to express member instance (C++) in Slice

For performance reasons, I use class instances that are direct members of other instances all over the place:

class A {int foo();};
class B {A bar;};
class C {B blah;};

What is the natural (with little boilerplate code) way to express this situation in Slice, so that, in the ideal case, remote calls look like the local ones, i.e.

C a;
a.blah.bar.foo()

I have a feeling that this pattern would have refcounting issues...

(I know I could have probably answered this question myself if I read the manual carefully, but I need a quick estimate of the amount of work needed to accomplish this in an elegant way.)

Thanks for any information!

Comments

  • benoit
    benoit Rennes, France
    Hi,

    Are the 3 class instances supposed to be distributed within different processes or will they always be within the same process? There are several ways to write the Slice for the classes you describe.

    Here are 2 examples which should highlight this:
    // Slice
    module FirstExample 
    {
    class A 
    {
        int foo();
    };
    class B 
    {
        A* bar;
    };
    class C 
    {
       B* blah;
    };
    
    interface MyIntf
    {
        void op(C* c);
    }
    }
    
    // C++
    MyIntfI::op(const CPrx& c, const Ice::Current&)
    {
         c->blah->bar->foo(); // The foo() invocation is remote here.
    }
    

    Second example:

    // Slice
    module FirstExample 
    {
    class A 
    {
        int foo();
    };
    class B 
    {
        A bar;
    };
    class C 
    {
       B blah;
    };
    
    interface MyIntf
    {
        void op(C c);
    }
    }
    
    // C++
    MyIntfI::op(const CPtr& c, const Ice::Current&)
    {
         c->blah->bar->foo(); // The foo() invocation is local here.
    }
    

    In the first example, the Slice uses proxies. The Ice object for A, B and C can be hosted in different processes.

    In the second example, the Slice uses class references. When a C instance is passed to the op() implementation, the whole object graph associated to C is provided to the op method.

    In any case there shouldn't be reference counting issues. See the sections starting at "Smart Pointers and Cycles" in the C++ mapping reference for more information.

    Cheers,
    Benoit.
  • Thanks for reply. I see. Thinking about it again, I was essentially asking if one can have proxies/references "to the middle" of objects. As both your examples use -> semantics, wheras I was looking for . semantics, I conclude that this is not directly possible. Probably the most natural solution is to write dedicated interfaces that expose those "members of a member (of a member)", or not? Unfortunately, this is boilerplate code, so I will consider autogenerating both the relevant part of slice and the corresponding implementation.
  • benoit
    benoit Rennes, France
    Sorry, the first example is broken... You can't directly access the attributes of a Slice class using a proxy. So the following doesn't work: "c->blah->bar->foo();"

    Instead you would need to specify accessors for each attribute. You would also typically instead just use Slice interfaces. So here's the correct first example:
    module FirstExample 
    {
    interface A 
    {
        int foo();
    };
    interface B 
    {
        A* getBar();
    };
    interface C 
    {
       B* getBlah();
    };
    
    interface MyIntf
    {
        void op(C* c);
    }
    }
    
    // C++
    MyIntfI::op(const CPrx& c, const Ice::Current&)
    {
         c->getBlah()->getBar()->foo(); // The foo() invocation is remote here.
    }
    

    Cheers,
    Benoit.