Archived

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

class with operations, Initialization

G'Day

How do I initialize a class after it has been populated but before an
operation on it? (Not populated by Freeze)

Situation:

...
class DateTime {
nonmutating short month();
nonmutating short year();
...
long store;
};
...

points of note:
1. using C++
2. 'store' maps to std::time_t
3. I'm not using freeze for this class.
4. I've registered a factory (DateTimeFactory)

At the time the factory instantiates the class, 'store' is not populated.

When an operation is dispatched to it, 'store' has been populated, but the
class is not initialized. That is, a private member struct in DateTimeI (std::tm)
has not been populated using 'struct tm *localtime(const time_t *timep);'.

pls refer to (Distributed Programming with Ice, p595, 21.5.6 Using a servant Initializer)

It seems what I need is a servant initializer (something similar to an
implementation of Freeze::ServantInitializer) to be installed with
the communicator(?). I have read a fair chunk of 'Distributed
Programming with Ice' but can't find a solution.

Your help would be much appreciated.

Cheers, Stuart.

PS, if the answer is trivial (or well documented), please excuse
me. I'm new to ice, distributed programming and C++. Ice
rulez :)

Come to think of it, I'm not sure if casting time_t to ::Ice::Long is portable all that portable.

Comments

  • Re: class with operations, Initialization
    Originally posted by StuartA
    G'Day

    How do I initialize a class after it has been populated but before an
    operation on it? (Not populated by Freeze)

    Situation:

    ...
    class DateTime {
    nonmutating short month();
    nonmutating short year();
    ...
    long store;
    };
    ...

    points of note:
    1. using C++
    2. 'store' maps to std::time_t
    3. I'm not using freeze for this class.
    4. I've registered a factory (DateTimeFactory)

    At the time the factory instantiates the class, 'store' is not populated.

    Your class is abstract because it has operations. In turn, this means that you must register a factory (as you say you did). The factory can initialize the class members because class members are public. So, to initialize the store member, you simply make your factory assign to the member once the factory has instantiated the class.

    pls refer to (Distributed Programming with Ice, p595, 21.5.6 Using a servant Initializer)

    It seems what I need is a servant initializer (something similar to an
    implementation of Freeze::ServantInitializer) to be installed with
    the communicator(?).

    For Freeze, the servant initializer is provided because Freeze instantiates the class, and Freeze cannot know how to initialize the members of a class. So two steps are needed to get a class instance off the ground: the instantiation (handled by Freeze) and the initialization (handled by the servant initializer). For classes not managed by Freeze, the instantiation and initialization are combined into a single step: the call to the factory for the class. So, make your factory assign whatever is appropriate for the class and you are set. (You can think of the factory as the default constructor of the class, if you like.)
    Come to think of it, I'm not sure if casting time_t to ::Ice::Long is portable all that portable.

    ::Ice::Long is a 64-bit type. On all platforms I know of, time_t is a 32-bit type that holds the number of seconds since the epoch (1 Jan 1970), so assigning a time_t to an ::Ice::Long should never cause a problem.

    Cheers,

    Michi.
  • Thankyou...

    Stuart
  • Sorry to bother you again.

    Just had a think about your reply and don't think I explained myself
    well enough.

    here is my factory create method:

    ObjectPtr
    DateTimeFactory::create(const string& type) {
    assert(type == DateTime::ice_staticId());
    DateTimeIPtr dtp = new DateTimeI();
    cerr << __FILE__ << ":" << __LINE__ << ", store: " << dtp->store << endl; // returns 0
    return dtp;
    }

    points of note:

    1. store is sent over the wire but has not been populated at the time
    factory creates instance of DateTimeI in the server. (not surprising)

    2. I need the following two lines executed in DateTimeI once 'store'
    is populated but before any operations on DateTimePtr. (this is the
    initialization I'm talking about)

    time_t ssEpoch = (time_t) store;
    _timeInfo = *localtime(&ssEpoch); // struct ::std::tm

    Thanks in advance.

    Stuart
  • I'm afraid the only solution is to call a method to execute this code manually (whenever you receive a DateTime as paramater or return value), or to use lazy initialization, i.e., execute this code whenever the first method on DateTime is called.

    Perhaps we should add a generic ObjectInitializer to Ice (i.e., not only for Freeze), that is called after the data members of an object have been populated.
  • Thanks Mark and Michi,

    I feared as much. One issue with using lazy initialization, is the
    accessors (eg year()), are no longer nonmutating. Not quite so clean.

    Thanks again. Stuart.
  • We decided to add a virtual operation ice_postUnmarshal() to Ice::Object, which is called after an object has been unmarshalled, i.e., after all data members have been populated. The default implementation will be to do nothing, but user code can override this method.

    Expect this in the next version of Ice.