Archived

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

Common interface for objects and proxies

I'm having trouble writing tests for servants written in C++ and afaict the issues would be similar for all statically typed languages.

If my slice is
interface Foo { int bar(); };
I get two classes, one in namespace IceProxy and another in IceDelegate, which are held by handles called FooPrx and FooPtr.

If I have a function which takes a FooPrx I have to code it as such.
Ice::Int doSomething(FooPrx const& fp) { return fp->bar(); }
To test it I cannot simply throw a FooPtr at it, I have to go through whatever it takes to get a working FooPrx before I can test anything. (Correct me if I'm wrong but I believe that means I have to create an object adapter and publish the object on it.)

In C++ can work around it by making my own base class and handle:
class Foo {
 virtual ~Foo() {}
 virtual int bar()=0;
};

typedef boost::shared_ptr<Foo> FooHandle;

template <class FP>
class FooImpl : public Foo {
public:
  FooImpl(FP fp) : fp_(fp) {}
  int bar() { return fp_->bar(); }
private:
  FP fp_;
};

template <class FP>
FooHandle toFooHandle(FP fp) {
  return FooHandle(new FooImpl<FP>(fp));
}

From looking at the slice generated code it appears that the Foo in namespace IceDelegate is a pure abstract base class (aka. interface) and so, with the tiniest bit of rearrangement, could be made a base of the Foo in IceProxy. This would unify FooPtr and FooPrx (which could then be a typedef) and vastly simplify the process of writing tests for us.

Any chance this might happen? (Soon?)

-Oliver

Comments

  • My understanding is that if you want to call an interface function you either need the servant itself or a proxy to the servant (which requires the servant be registered with the object adapter).

    Passing the servant around so your server application does not need to create a proxy and call the interface method might not be the best idea. For one, you can't then later migrate that servant's processing onto other hardware.

    Not wanting to register the servant with an object adapter means only the application that created the servant can use it. Why then create an Ice interface or class?
  • chow wrote: »
    Passing the servant around so your server application does not need to create a proxy and call the interface method might not be the best idea. For one, you can't then later migrate that servant's processing onto other hardware.

    In general I agree, there is not much reason to write code which expects servants rather than proxies, but it would be better still not to be forced to choose.

    Unit testing is a case where, as a rule, you try to carry as little additional baggage as possible. With a common base class almost all our code would simply code to that interface and it would be easy to pass in servants or mocks for testing.
    chow wrote: »
    Not wanting to register the servant with an object adapter means only the application that created the servant can use it. Why then create an Ice interface or class?

    For tests. It's not so important for testing a stand-alone class. It's when instances of one class reference others that being forced to always reference a proxy becomes inconvenient.
  • Assuming you take care to destroy things in good order (see 34.7), define a proxy to class B in class A and initialize it in the factory create for B. A will have to be registered in the object adapter first for this to work. See also the examples in section 39.4.

    class A {
    };

    class B {
    A aProxy;
    };