[Kryonet] Any way to avoid instanceof check?

Hi guys,

while thinking about how to use Kryonet for sending many different objects between the client and server I wondered how to avoid the instanceof check.

Is this even possible at all?

From my current thoughts I came up with the idea of having a simple packat class that encapsulate an op-code and some arbitrary data. In that case I would end up with some kind of lookup table to create my corresponding object.

However I really hope there is some more easier/fluent way of handling many different data objects.

Greetz
Evil-Devil

KryoNet does exactly that behind the scenes: a lookup table with class-ids to instanciate a class. Why would you want to add an abstraction layer that replicates this behavior?

The tutorials don’t state that it is doing something like that. I’ve seen the serialize stuff and so on. But no real example. Every example, even those shipped with kryonet have a long list of conditionals with instance of checks


[...]
public void received (Connection c, Object object) {
    if (object instanceof MyObjectA) { ... }
    if (object instanceof MyObjectB) { ... }
    if (object instanceof MyObjectC) { ... }
    if (object instanceof MyObjectD) { ... }
    [...]    
}
[...]

That is why I’m asking. Maybe I just haven’t found the right source of documentation/tutorial.

Is an if-else chain really a problem in your code, or is this premature optimization?

It is not about the if-else chain. It is about the annoying instanceof checking.

I was hoping there is some kind of mechanism where I can just plugin my method and object. And as you said Kryonet will take core of it with its own lookup table.
If reasonable even with an delegate interface.


public void updateLocation(Connection c, Location location) {
    // location might be serialized
    c.send(location)
}

public void updateInventory(Connection c, Item item) {
    // serialized object
    c.send(item);
}

public void sendChatMessage(Connection c, ChatMessage msg) {
    // serialized object
    c.send(msg);
}

Depending on the actual project I might end up with > 100 type of objects to check. Such a big conditional is not maintainable. Even when using a lookup table for just the conditional check o_O

And it is not clean code :wink:

Reflection to the rescue!

Old:


if(packet instanceof Location) {
   this.updateLocation(conn, (Location)packet);
}
else if(packet instanceof Item) {
   this.updateItem(conn, (Item)packet);
}
else if(packet instanceof ChatMessage) {
   this.updateChatMessage(conn, (ChatMessage)packet);
}

New:


String packetType = packet.getClass().getSimpleName();
Method method = this.getClass().getMethod("update"+packetType, new Class[]{Connection.class, packet.getClass()});
method.invoke(this, new Object[]{conn, packet});

Thanks riven. That might be my rescue. That way I can define a common interface and still have small maintainable source :slight_smile:
The overhead caused by the reflection on the serverside is probably not that big. But that would be another issue when it arise.

Thx Riven!

Just think about the packet rate on a server… Even when handling 1000 packets per second the reflection overhead will be insignificant.

Wow! I have always wanted to do something like this, I just didn’t know that it existed!

You could do this in a “cleaner” way by defining a packet interface that all packets implement with a simple handle() function.


public interface Packet{
    public void handle();
}

public class LocationUpdate implements Packet{
    
    ...
    
    public void handle(){
        ...
    }
}

etc

So whenever you get a packet, you simply cast it to your Packet interface and call handle() on it.

Wouldn’t even need to cast, right? Isn’t that the whole point of common interfaces?

EDIT: (oh, well if it was received as an Object, then yeah I guess it would…)

I don’t use instanceof. Instead I use an int value indicating type. int comparison is cheaper than reflection or instanceof.

Still using “if” statements is also slow so you should use them only when you need them. You can often replace the if chain with an an extended method of the same name.

if(o.type == o2.type)
{

}