Archived

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

polymorphic methods via inheritance - object factory?

Inheriting base-class data members form slice-generated classes is useful, but so would be inheriting the methods. Well, inheriting the abstract/generated-methods is not useful, but inheriting from a class derived from the generated class might be useful - that sounds confusing (BTW, I'm talking about local, non-network, server-side methods here).

Say I've got base class A from which classes B and C are derived, and I want A to do some common useful method like 'process' how do I inject that into this slice-based architecture? I'll of course really be instantiating classes Bprime and Cprime from B and C respectively via the object factory to get useful methods beyond the abstract methods slice generates. Do I somehow need to derive an Aprime from A to do define this 'process' method? If so, how does this Aprime get created (from the object factory?), and how do Bprime and Cprime then inherit from Aprime instead of just A (or rather from B and C where these now derive from Aprime instead of A)?

I'm clearly missing something here (that's what I get for working on Sunday). Hopefully I'll figure this out (then will delete this posted question), but in the meantime, if you can shed some light to clear away my confusion, I'd appreciate it! Again, this question is not so much about network operations, but about stuff in the slice world (I'm working in java on the server side, but I supposed the same question could get posed on the client side).

Comments

  • Here's some psuedo code to go with the above post (past the time limit to edit):

    slice:
    module Module {
    class A {
    string name ;
    void process() ;
    } ;
    class B extends A {
    string info ;
    } ;
    class C extends A {
    string otherInfo ;
    } ;
    }
    ... interface, etc...

    java-server:
    ... define class BI extends B { public void process( Ice.Current c ) ...
    ... ObjectFactory to map ::Module::B to ::Module::BI, etc...

    how to I define method process() for class A (or create/derive from A')?

    Perhaps this is not possible and I should be using application-side classes instead of trying to mix this biz/logic in with Slice-generated classes.

    I have also just now read about Tie classes (Slice 12.7) where, in java since there is no multiple inheritance (for the skeleton and impl), a delegate class can be used for one. This seems complicated for my simple scenario and needs but perhaps it is an answer...
  • As you already worked out, the way to get your own class implementation instantiated is to add a factory for it to the object factory map.

    In C++, you can use ladder inheritance to achieve what you want, that is, AI derives from the A skeleton, and BI derives from both the B skeleton and the AI implementation.

    However, in Java, due to the lack of multiple inheritance, you cannot do this and you must use delegation to get the same effect. You can either use a tie to do this, or implement your own class that forwards to the appropriate implementation (which would end up looking much like tie, so you might as well use the tie).

    Cheers,

    Michi.
  • Thanks! I think I've got it - using Ties/delegations since we can't overuse inheritance in java.

    But I'm still a little confused when creating the servant from an object factory (may just be my rookie java skills). The tie servant is of type Ice.TieBase, but the object factory's create method rejects that return type and wants an Ice.Object, and apparently Ice.TieBase is not an Ice.Object (I couldn't find the definition of Ice.TieBase).

    Also, the set_delegate method won't invoke on an object of type Ice.TieBase, even if it was created to be the most specifically derived form of Ice.TieBase.

    So instead of using the type Ice.TieBase (which would be
    really convenient), I use the most specific/derived Ice.TieBase type (perhaps to ensure it implements all the ops) then assign that to an Ice.Object upon return from the object factory's create routine (for some reason this assignment works better than letting the return implicity coerce the value).

    Am I doing something wrong, or can I do this better? Thanks again, -L.
  • matthew
    matthew NL, Canada
    I'm not really sure what you are asking. What you are supposed to do is "tie" the implementation to the Ice object using the generated tie object (which internally delegates all method invocations to the implementation). Please see the attached example which re-implements the hello demo server using tie.
  • Sorry, I should have used more code and less words ;-).

    My questions is about the create type in ObjectFactorys when using Ties.

    Thanks for the Tie example - I've modified it to use an ObjectFactory to
    create some base and derived classes for the serverant and implemenation.
    It's working (although I didn't bother with the client side, as I think
    I need to run slice one with --tie and once without?),
    but I wonder if the ObjectFactory could be writtten better.

    Any of your comments are appreciated - many thanks.

    (Also thanks for tie="on" as I couldn't find doc on Slice2JavaTask).

    Here's the crux of my ObjectFactory code quandry inline:

    /* It'd be nice to type the tieServant as generically as possible
    (Ice.TieBase) so as much of the glue code can be factored-out as possible.
    It's also strange that it can't be returned directly but must be assigned
    to an Ice.Object first. The delegate probably has to be typed more
    specifically so the impementation of methods/operations can be enforced.

    Ice.TieBase returnIceTieServant = null ;
    Object delegateImpl = null ;
    */
    // ? Ice.TieBase returnIceTieServant = null ;
    // ? Message returnIceTieServant = null ;
    // ? Ice.ObjectImpl returnIceTieServant = null ;
    Ice.Object returnIceTieServant = null ;
    // ? (needs to impl ops) Object delegateImpl = null ;
    MessageImpl delegateImpl = null ;
    if(type.equals("::Demo::Message"))
    ...
  • matthew
    matthew NL, Canada
    Hi Lance,

    The ObjectFactory should look like:
        public Ice.Object
        create(String type)
        {
            if(type.equals("::Demo::Message"))
            {
                    _MessageTie obj = new _MessageTie();
                    MessageImpl impl = new MessageImpl(obj);
                    obj.ice_delegate(impl);
                    return obj;
            }
            if(type.equals("::Demo::DerivedMessage"))
            {
                    _DerivedMessageTie obj = new _DerivedMessageTie();
                    DerivedMessageImpl impl = new DerivedMessageImpl(obj);
                    obj.ice_delegate(impl);
                    return obj;
            }
            return null;
        }
    

    This is a little more complex than usual because you need access to the object itself for the class state. Making this code more generic doesn't really simplify the code as then you'd need more casts as you've found out.

    Furthermore, your MessageImpl should not store the Ice.TieBase, instead you should refer to the object type, since you need the state (delay in this case).
    public class MessageImpl implements _MessageOperations
    {
        Message _self;
    
        public MessageImpl(Message obj)
        {
            _self = obj;
        }
    
        public void
        process(Ice.Current current)
        {
            System.out.println("Procssing biz logic...");
        }
    }
    
    class DerivedMessageImpl extends MessageImpl implements _DerivedMessageOperations
    {
        DerivedMessage _self;
    
        public DerivedMessageImpl(DerivedMessage obj)
        {
            super(obj);
            _self = obj;
        }
    
      public void
        process(Ice.Current current)
        {
            System.out.println("Derived Procssing biz logic...");
        }
    }
    

    Also note that this particular example is not a good example for tie, as you are not really inheriting anything from the base implementation (that is you are re-implementing process in the Derived).

    Your demo also forgot to register the type ids for object factory. Furthermore, you should probably use ice_staticId() instead of hard coding the type id strings. That is:
    public Ice.Object
    create(String type)
    {
        if(type.equals(Message.ice_staticId())
        {
    

    With respect to your client, you do not need to use differently compiled slice. Using --tie only adds the tie generated classes, it doesn't take anything away. The reason why your client didn't compile is because you cannot directly instantiate an abstract class (that is a class with a method).
  • Thanks - all the ideas and improvements in your response were great!

    I got a little confused throwing together the Tie/delegate changes to the hello client about not being able to instantiate the abstract class in java (slice class with a method). I think this is because I've been instantiating such an abstract class on the ObjC side! Correct me if I'm wrong, but this works because ObjC is looser in some ways, and as long as I don't call the method on the client side, it will work fine (rather than defining a bunch of empty Impls).

    It makes sense in my prototype to have dual inheritance trees (lacking multiple inheritance in java) - one for data and one for methods/biz logic, so the Tie feature is nice. I'm accurately defining the reference type to the Tie object in my Impl which works well, and I'm comparing Ice_staticID instead of hard strings in the ObjectFactory which will save me pain from typos.

    Thanks again for the support!