The Design of Software (CLOSED)

A public forum for discussing the design of software, from the user interface to the code architecture. Now closed.

The "Design of Software" discussion group has been merged with the main Joel on Software discussion group.

The archives will remain online indefinitely.

mantaining a consistent type identifiers accross subclasses

Hi

I'm facing a recurrent design/management problem in a large middleware framework. Suppose an abstract class which is expected to have several subclasses developed by the people who uses the framework (and therefore, not under my control).

This class and its child classes has an int field whose value should be an enumeration (that is, has a valid set of values). Each subclass adds its own values to the enumeration and no two subclasses should add the same (or at least, not inadvertently) 

This problem arises in diverse contexts:
1. The super class is an generic Event class with many subclasses that represents especific types of events triggered by other components. In some cases, a subclass represents a type of event, in others, several types of events share the same subclass (same implementation) but are semantically different (need to know the exact type because there are per type processing rules)

2. The super class is a Message class (used to communicate components across the network).  The int file defines the type of event. As with events above, in some cases several message types share the same implementation (but are semantically different)

3. Class A is a Job class, which represents the execution status of a process. Subclasses are platform dependent implementations. The int field is the status of the job (e.g. "running", "ended", etc). Different implementations might add new status (for example, "held", or "migrated") which are supported only in this platform or are supported by several platforms.

In all the above cases, I would like to be sure that two subclasses do not use accidentally the same values for the int (for example, that "held" and "migrated" are the same value)

Subclasses are expected to grow in the future as other people use the framework, so I can't define the values in advance.

Unfortunately, in java Enums cannot be dynamically extended.

Any suggestion on how to manage this on the large run?
Pablo Send private email
Friday, July 04, 2008
 
 
Generally you use abstract and/or virtual function *instead of* having an enum in a switch statement.

If you (the superclass) don't know what the base class is, then I don't see why you need to keep an "int" to represent its type (what kind of processing would you do on that int)? If a subclass wants some kind of int, then let the subclass define and process it.

Instead of using an int then, apart from virtual functions, maybe you can find some use java 'class' literal.
Christopher Wells Send private email
Friday, July 04, 2008
 
 
Can't you let the base class hand out 'tokens', so that there is one point (the base class) who can control which derived class uses what number as id? This would have to be done at runtime and it would not give you type safety.
Joske Vermeulen
Friday, July 04, 2008
 
 
Christopher, I don't see how using virtual functions will help me to solve the problem. If each subclass is free to return any value, conflicts can still arise.

Joske, I considered this option. But I saw the token handling a little bit complicated.

By now, I came to a "solution": I created a parallel hierarchy of what I call EnumeratedValues (modeled after the Enums in java). Each value has a name and a int value. The class is abstract and all their methods are final.

Each subclass in the original hierarchy (the one I explained in my previous post) can create its own subclass of this EnumeratedValue or use any super class. It can also create as many instances (different values) as needed, each with a name.

The trick is that the EnumeratedValue class generates a name concatenating the name of all classes in the  hierarchy and an integer value using the hash of this full name.


An example will help to clarify this. For event management I have now this hierarchy:

Event
 |- NetworkEvent

and this other

EnumeratedValue (abstract)
  |- EnumeratedEventType (abstract)
      |- EnumeratedNetworkErrorEventType


Event is defined as this constructor

private EnumeratedEventType type;
private String description;

Event(EnumeratedEventType aType,String aDescription){
  this.type = type;
  this.description = aDescription;
}

NetworkEvent is defined as follows:

public static EnumeratedNetworkEventType TIME_OUT = new EnumeratedNetworkEvent("TIMEOUT");

public static EnumeratedNetworkEvet BROKEN = new EnumeratedNetworkEvent("BROKEN");

public NetworkEvent(EnumeratedNeworkEvent aType, String aDescription, Sring anAddress){
      super(aType,aDescription)
      this.address = anAddress;
}

Notice that the BROKEN instance the EnumeratedValue constructor will generate  has a full name of EnumeratedValue.EnumeratedEventType.EnumeratedNetworkEventType.BROKEN
 and will generate an integer based on it.

to generate an network event you do something like:

Event event = new NetworkEvent(NetworkEvent.BROKEN,"foo","10.0.0.1");


and later I can ask:
if(event.getType.equals(BROKEN))

looks complicated (and maybe I'm not explaining it well) but I implemented it in a rather short time and I've been testing if and seams to work!
Pablo Send private email
Friday, July 04, 2008
 
 
Sorry, my last post there is a sentence which is unreadable because I cut/pasted it to reorganize the text! sorry!


"Notice that for the BROKEN instance the EnumeratedValue constructor will generate  a full name of EnumeratedValue.EnumeratedEventType.EnumeratedNetworkEventType.BROKEN
 and will generate an integer based on the hash of this name"
Pablo Send private email
Friday, July 04, 2008
 
 
> Christopher, I don't see how using virtual functions will help me to solve the problem. If each subclass is free to return any value, conflicts can still arise.

I meant using virtual functions, instead of (not as well as) using an enum. Instead of:

  //do something which depends on the type of message
  switch (message.type)
  {
    case 1:
      handle_it_this_way(message);
      break;
    case 2:
      handle_it_that_way(message);
      break;
    ... etc. for other types of messages that we don't even know about ...
  }

Do it this way instead:

  //do something which depends on the type of message
  //where that 'something' is defined by the subclass
  //which implements the virtual_method method
  message.virtual_method(this);

Sorry, I apparently don't undertand your use cases, i.e. I don't undertand your needing or wanting an enum.
Christopher Wells Send private email
Friday, July 04, 2008
 
 
I'm not a Java person, but if I understand your needs correctly, you want something that:

1. Is extendable by people subclassing your work
2. Is a set of repeatable, unique integers
3. The values in the extensions do not intersect with each other
4. Will be identified by name in code

If that's true, then your idea of generating a hash value based on the name sounds pretty good. 

The only limitation I see is that the reverse mapping of value to name may not be possible because it's defined in a subclass that the calling code doesn't have access to.  Which, in a messaging situation, is probably OK as its the "I don't know what this message is" scenario.

Some suggestions:
- For performance reasons, generate the hash values only once & store them in a dictionary or two.
- To protect against silly coder mistakes, do the hash against a case-insensitive version of the name.
xampl
Friday, July 04, 2008
 
 
Whoops - one gotcha.  If two extensions both define a "GetWidgetVersion" message, it'll hash to the same value.  If the extensions aren't compiled together, you won't get an error.  So you might need a special build step that just compiles the base class & all extensions to protect against this.
xampl
Friday, July 04, 2008
 
 
Christopher

"Sorry, I apparently don't undertand your use cases, i.e. I don't undertand your needing or wanting an enum."

The solution you propose is fine if the classes are able to define all the intended behaviors in such virtual methods.

But in the cases I mentioned, other classes are the responsible of such behaviors. For instance, an Event doesn't know how the application wants to handle it. The person who creates the NetworkEvent class can't foresee any possible way of handling it, ranging from ignoring to logging it, to triggering a response action.


Pablo
Pablo Send private email
Friday, July 04, 2008
 
 
xampl

"The only limitation I see is that the reverse mapping of value to name may not be possible because it's defined in a subclass that the calling code doesn't have access to.  Which, in a messaging situation, is probably OK as its the "I don't know what this message is" scenario."

Good point!
Pablo Send private email
Friday, July 04, 2008
 
 
> For instance, an Event doesn't know how the application wants to handle it.

In that case, perhaps use the "double dispatch" idiom (a.k.a. "multiple dispatch") between the Event subclasses and the Application class.
Christopher Wells Send private email
Friday, July 04, 2008
 
 
Java has this thing called "inheritance". Using it, you have a class called 'Event' and can then have subclasses such as 'NetworkEvent' and 'KeyboardEvent' and so on. You can have arbitrary numbers of subclasses, and each subclass can have more subclasses that derive from it.

Then you go to our friend google, and look for "java find subclass". Two clicks and you'll find yourself here:

http://java.sun.com/j2se/1.3/docs/api/java/lang/Object.html

for the getClass() method and then here:

http://java.sun.com/j2se/1.3/docs/api/java/lang/Class.html

for the getClasses() method.

(If it hadn't been several years since I've used Java I could have skipped the google step and gone straight to the documentation. But given the way Java works, anyone who doesn't have some idea about the Class and Object classes and their methods should simply be shot.)

Putting this together, given an instance of a subclass of Event, you can easily find all the classes that the specific class inherits from, and use that to perform any class-specific code that genuinely has to depend on the specific subclass.

See? every object has something referred to as a "type" or a "class" already, so rolling your own "class identifier" is an entirely pointless waste of time. You're not just reinventing the wheel - you're reinventing it with three sides and setting it on fire then wondering why its not such a smooth ride as the old-fashioned wheel that you thought had to be replaced.

(Criticisims of this approach are correct, valid, and I agree completely. But why should we force an enterprise developer building a "large framework" to use sensible practises that the rest of the civilised world considers standard? And, if nothing else, if he simply must do it then exploiting the Java language design is slightly less evil than a scheme that introduces a dependancy between every single subclass across all applications, or goes converting strings to integer IDs at run time.)


Also, a framework built by someone determined to reinvent something as basic as subclassing, because he doesn't know the features of his own development system? Yep, that'll end well.

Also, I'm being a little harsh and even showing a hint of sarcasm. I might be nice to a student - but once you're a professional writing "frameworks" for many people to use, you'ld better be ready for more than just a hint of sarcasm and you'ld better be damn good, to avoid wasting the time of the people using your code. They have enough trouble with their own code without having to trim the corners off your triangular wheel to get it to work.

Sunday, July 06, 2008
 
 
"Java has this thing called "inheritance". Using it, you have a class called 'Event' and can then have subclasses such as 'NetworkEvent' and 'KeyboardEvent' and so on. You can have arbitrary numbers of subclasses, and each subclass can have more subclasses that derive from it."

I see, you now fell SO SMART and SO COOL, don't you?

Before trying to ridicule someone, at least be sure you understand the question and that you solution is nonsense.
Pablo Send private email
Monday, July 07, 2008
 
 
"In that case, perhaps use the "double dispatch" idiom (a.k.a. "multiple dispatch") between the Event subclasses and the Application class." Christopher Well

I saw the multiple dispatch idiom, which seams to address the same problem as the Visitor patten. It doesn't address (directly) the problem I have (maintaining a consistent enumeration across  subclasses), however, it is a nice way to build the applications I have in mind (for example, the event processing one).

However, that in order to do so, I would probably still need to create a sub class hierarchy which basically resembles that of the enumeration I proposed.  That is, the visitor pattern relies on the subclass hierarchy and in my case, this means that this hierarchy should reflect the different types (which not necessarily match the implementing classes). Remember that event when a class implements two event classes, those events are semantically different and might require different treatment.

Am I missing something in you proposal?
Pablo Send private email
Monday, July 07, 2008
 
 
> However, that in order to do so, I would probably still need to create a sub class hierarchy which basically resembles that of the enumeration I proposed.

Yes. I thought that you *wanted* to define a subclass hierarchy: your OP said that you wanted to define a subclass hierarchy, and the question was how to define a unique ID for each subclass.

> even when a class implements two event classes

I think you've said this more than once, and I don't understand it: you're not being entirely precise (how can "a class implement two classes"?). Perhaps if you gave a pseudocode example that would make it clearer.

> Am I missing something in you proposal?

Double dispatch is useful in the following situation (which I thought was your use-case):

* You're designing a base/superclass (e.g. "Event") ... you don't know what subclasses will be written in the future.

* People will define subclasses (e.g. "AsteroidEvent", "SpaceshipEvent", etc.). More and more subclasses will be written. There may be subsubclasses (e.g. "BigSpaceshipEvent" and "SmallSpaceshipEvent").

* Someone will write an application. The application *will* know what subclasses exist, and know how it wants to process subclasses.

You want an enumerated ID field so that the application can do subclass-specific handling, for example:

class ApplicationLogger
{
  void log(Event event)
  {
    //logging depends on the type of event
    switch (event.id)
    {
    case EventIdSmallSpaceshipEvent:
      smallSpaceshipEventLog(event);
    }
  }
}

Double dispatch would use virtual functions instead of an enumeration, for example:

* The application invokes a virtual method of the subclass
* The virtual method of the subclass invokes the right application method

class ApplicationLogger
{
  void log(Event event)
  {
    //logging depends on the type of event
    event.virtual_log(this);
  }
  //special handling for SmallSpaceshipEvent classes
  void handle(SmallSpaceshipEvent event)
  {
    smallSpaceshipEventLog(event);
  }
  //default handling for other classes
  void handle(Event event)
  {
    defaultLog(event);
  }
}

class Event
{
  abstract void virtual_log(ApplicationLogger logger);
}

class AsteroidEvent
{
  virtual void virtual_log(ApplicationLogger logger)
  {
    logger.handle(this);
  }
}

class SmallSpaceshipEvent
{
  virtual void virtual_log(ApplicationLogger logger)
  {
    logger.handle(this);
  }
}

Alternatively, instead of double-dispatch and instead of enumeration, Wikipedia suggests that you can use Java's instanceof keyword; for example you can rewrite my first switch statement above to use instanceof instead of usng an enumeration, like this:

class ApplicationLogger
{
  void log(Event event)
  {
    //logging depends on the type of event
    if (event instanceof SmallSpaceshipEvent)
    {
      smallSpaceshipEventLog(event);
    }
    else if (etc.)
    {
      etc.;
    }
  }
}
Christopher Wells Send private email
Monday, July 07, 2008
 
 
"WI think you've said this more than once, and I don't understand it: you're not being entirely precise (how can "a class implement two classes"?). Perhaps if you gave a pseudocode example that would make it clearer."

Christopher, I said in my first post that my problem was not to define a class hierarchy, but to assure a consistent enumeration across such class hierarchy for an integer attribute I called "type", which is a completely different problem! I gave three different use cases when this is needed, even when they are rather similar.

I'm not saying a class implement two subclasses. I said that a class might be responsible for more than one value in the "type" enumeration.

For instance, in the events case, I have this hierarchy:
Event
 |-ApplicationEvent
    possible types: RUNTIME_EXCEPTION, CONFIGURATION_EXCEPTION, USER_CANCELED, etcetera 
 |-NetworkEvent. TIME_OUT, RESET, etcetera.

MY PROBLEM IS: how to assure that the all the values of ApplicatioEvent and NetworkEvent types are different?

Please notice that new subclasses and  therefore event types will be defined by the users of the framework. So basically I don't want a programmer to inadvertently assign the same type value to an existing event. 

This like to have an Enumeration defined across the hierarchy.

Why is this useful? well, because this type can be used as keys in queries, for example, so I want to be user that I only retrieve the expected event types. 

I think I found a way to solve this, which is basically a extensible enumeration and it is working fine.

Thanks for your time and patience.

Regards
Pablo Send private email
Monday, July 07, 2008
 
 
From the OP:

"Suppose an abstract class which is expected to have several subclasses developed by the people who uses the framework (and therefore, not under my control)."

He then babbled on about needing identifiers for each subclass so that class-specific code knows what specific subclass it is dealing with.


Yes, the OP stated that he is creating a class hierachy, and I feel SMART and COOL and BRILLIANT and SUPERIOR for pointing out that his reinvented wheel only has three sides and that I feel sorry for any of his victims. Er, by "victims" I mean the poor souls forced to use his crappy code.

Monday, July 07, 2008
 
 
MY PROBLEM IS: how to assure that the all the values of ApplicatioEvent and NetworkEvent types are different?


It's called a subclass.  Look it up.

Monday, July 07, 2008
 
 
1. Given the function you're describing, don't pass an enum to it from the subclass.  Use instanceOf to check what the current instance is.  Then the class heirarchy itself becomes your enum, and it's guaranteed to be unique.

2.  Don't write the function at all.  If the parent class needs to know too much about child classes, something has gone wrong with your inheritance design.  For example, instead of this:

class MyParent
{
  void MyMethod(int EnumValue)
  {
      // do some work

      switch(EnumValue)
      {
        case 1:
            // one child class
            break;
        case 2:
            // different child class
            break;
        default:
      };
 
      // do more work
  }
}
/////////////////////////////////////////
Do this:

class MyParent
{
    void MyMethod()
    {
        // do some work
   
        MyChildMethod();

        // do more work
    }


    virtual void MyChildMethod()
    {
      // default implementation
    }
}
////////////////////////////////

_ANYTHING_ you want to do in the switch from the first example can be done using code from the child example.
Joel Coehoorn Send private email
Tuesday, July 15, 2008
 
 
I agree with Joel Coehoorn: If your parent class needs to know anything about its child classes, then something is cockeyed.

It strikes me that your events are actually states.  Perhaps this is obvious or just a matter of terminology.  However, you might think about using the State pattern.

It seems the State pattern would enable you to add states (events?) at will.  To address your problem of some master object knowing all the states, you can move this functionality to the states themselves.  That is, each state object knows to which state(s) it should transition and under what circumstance.
Dave K Send private email
Wednesday, July 16, 2008
 
 
I'm surprised of three things that becomes apparent from most of the answers to my posting:

1. How some people fells superior just because knows a bunch of patterns and thinks that the design process is limited to  finding the "right pattern".


2. Most people don't make any effort to understand the problem. This is even more curios when considering that, according to most of the pattern literature, the most  difficult part of using patterns is understanding the context and figuring out the applicability to a given situation.

My problem is not about subclasses. Is about maintaining a consistent set of enumerated values in a field across a whole hierarchy. Two different problems.

3. Most of the comments assumed that my problem was about processing some kind of state. Have you noticed that most systems needs to deal with issues like persistence and sending data over the wire? In my case, this is where the problem really arise

In any case, thanks for the people who tried to help seriously.
Pablo Send private email
Wednesday, July 16, 2008
 
 
"Yes, the OP stated that he is creating a class hierachy, and I feel SMART and COOL and BRILLIANT and SUPERIOR for pointing out that his reinvented wheel only has three sides and that I feel sorry for any of his victims. Er, by "victims" I mean the poor souls forced to use his crappy code."

My advise: go a get a life. A real one, on which you don't need to make such pathetic comments to fell "superior".

by the way, I guess you just found pattern a couple of years ago, didn't you? I suppose is a matter of time that you realize that are coming some 10 years late to the party and that your comments are utterly irrelevant now days.
Pablo Send private email
Wednesday, July 16, 2008
 
 
> "My problem is not about subclasses. Is about maintaining a consistent set of enumerated values in a field across a whole hierarchy."

If that's all the problem is, than just define the enumeration in the same place or as a member of the parent class.  Child classes should not be adding to it.
Joel Coehoorn Send private email
Wednesday, July 16, 2008
 
 
If I'm reading the problem correctly, you should be able to use a combination of inheritance & java-style enum (I'm a c# guy).  Is something like this what you're looking for?

public abstract class CoreDefinition
{
    protected CoreDefinition(string name)
    {
        _name = name;
        if(_list.Contains(name))
        {
            //throw Exception
            //yes, throwing exceptions in constructors
            //is bad, but I'm trying to find the right
            //path
        }
    }

    private readonly ArrayList _list = new ArrayList();
    private readonly string _name;
    public string Name { get { return _name; } }
}

public class ClassA : CoreDefinition
{
    private ClassA(string name) : base(name)
    {
        List.Add(this);
    }

    public static readonly ArrayList List = new ArrayList();
    public static readonly CoreDefinition Unused = new ClassA("Unused");
    public static readonly CoreDefinition Test = new ClassA("TestName");
    public static readonly CoreDefinition TestNoNegativeNumbers = new ClassA("TestName1");
}

public class ClassB : CoreDefinition
{
    public ClassB(string name) : base(name) { }
    public static readonly CoreDefinition ItemA = new ClassB("ItemA");
    public static readonly CoreDefinition ItemB = new ClassB("ItemB");
}


Then you can access the "Enum" like this:

ClassA.Unused
ClassA.Test
ClassB.ItemA
foreach(object x in ClassA.List)


you could also have the "master list" in the CoreDefinition store a reference to the subclass (e.g.  like the ClassA constructor).  That way, when you need to find the right class, you iterate the master list in the base class.
Another Anonymous Coward
Thursday, July 17, 2008
 
 
Mr Anonymous

He's talking about CROSS tree identification not DOWN tree identification of handling a type based on a flag.

A defines values 1, 2, 3 that it handles
B inherits A, defines values 4, 5, 6 that it handles
C inherits A, defines values 7, 8, 9 that it handles.

He considers it an ERROR if C was to handle 5 as then both B and C would claim that they handled the same thing, but would very likely handle it differently.

This makes sense if you are queuing a payload to a database (for example) for later retrieval, then iterating over a set of handler classes to determine who actually should handle it.

Personally, I've done that in the past using the full class name. This is similar to what you propose, but does nto require the application to know at compile time about all possible subclasses, which is what seems to be his issue, that someone can implement new classes that inherit from his base classes, or indeed classes of his own that inherit from those base classes.

I'm not sure what the reason is for allowing a class to handle more than one state, as that would probably simplify the problem.
Roger Willcocks Send private email
Thursday, July 17, 2008
 
 
Roger

"I'm not sure what the reason is for allowing a class to handle more than one state, as that would probably simplify the problem."

As this is a framework, I don't want to force this "one value per class" restriction, as the value is not always a state (in this case your suggestion makes a lot of sense), but in other cases the value is just a "type". Actually, In the several subclasses I 've already implemented, most of them implement more than one type.

"This is similar to what you propose, but does nto require the application to know at compile time about all possible subclasses"

In my approach, subclass only need to know its parent class, what makes sense!

Joel
"If that's all the problem is, than just define the enumeration in the same place or as a member of the parent class.  Child classes should not be adding to it."

Well, I didn't want that the user of the framework have to change a class in the framework for using it!
Pablo Send private email
Friday, July 18, 2008
 
 

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics
 
Powered by FogBugz