On Dictionaries and Events

This month featured two really intense coding experiences, one of which was a prototyping week that Christian Oeing and me used to start an own software project. The other one was the Daedalic Game Jam, and I want to summarize the learnings of both events in this post.

.NET Dictionary Lookup Performance

First of all, I got to learn how to work with the less obvious functions provided by generic .NET dictionaries. Consider the following code snippet that is actually taken from code that I’ve written before the prototyping week:

This code actually performs two dictionary lookups in order to retrieve a specific value: One is made by ContainsKey, while the other is part of the dictionary indexer used to retrieve the value. You can prevent this by using TryGetValue instead:

TryGetValue will try to retrieve the value from the dictionary and return null if it fails to do so. According to official .NET documentation, TryGetValue is more efficient in case you often try to access values that turn out not to be in the dictionary.

Another speed-up could be achieved by changing the way I iterated over dictionary entries. Take a look at the following code snippet:

This foreach loop iterates over all keys of the dictionary, and looks up the associated values after. However, if the whole dictionary is iterated over anyway, we can do completely without lookups:

By iterating of the key-value-pairs themselves, we can access the content of the whole dictionary without spending time on a single lookup.

Exceptions During Event Queue Processing

One week later, at the Daedalic Game Jam, I used an event system for processing user input and game events.

So far, so good. If any new events have occurred, all of them are processed by passing them to the appropriate listeners (using TryGetValue 😉 ). Additional events that occur during event processing are added to the newEvents list, preventing concurrent modification issues and maintaining the correct processing order.

However, this method might cause severe problems in one case (and did so during the game jam, actually 😉 ): If any of the event listeners throws an unhandled exception, this will cause the event processing loop to break and never recover! If ProcessEvents is called in every frame, it will fail at the exact same event every time. Even more, the same events will be processed over and over and over again, because the system never gets to clear its event queue.

Clearly, handling errors should be in the responsibility of the specific event handler in this case. However, if any co-worker of yours just forgets to do so for any tiny exception that might occur, your whole game will break and you can’t do anything to recover in that case. Thus, it might me a good idea to wrap the eventListeners(e) call with a try-catch-block, logging any exceptions the listener causes and at least go on processing the remaining events and clearing the queue.

Author: npruehs

Nick Pruehs is a Co-Founder of Slash Games, Hamburg. In 2009, he graduated as “Best Bachelor” in computer science at Kiel University. Two years later Nick finished his master’s degree in “Sound, Vision, Games” at Hamburg University of Applied Sciences, becoming the Lead Programmer of Daedalic Entertainment shortly after.

2 thoughts on “On Dictionaries and Events”

  1. These foreach loops are actually one of the cases where I love to use “var” as type declaration. It’s just so much easier to read.

    I stumbled upon the “exception during event processing” in Chained, too. However not the exact case, because our events are dispatched immediately. Still, if one of the callbacks throws an exception, the following ones are not called. Did you find a solution for this? I thought about not using += on a delegate and rather store a List of all individual delegates. Haven’t tried it yet though.

    P.S. Is that check for != null in line 42 in the last code block necessary?

  2. Yes and yes! 🙂

    Wrapping the eventListeners(e) call by try-catch and just logging an error in the catch block now gracefully allows our game to keep running. However, it’s not guaranteed that it still behaves as expected, of course.

    The null check is necessary in case nobody has registered for the fired event. The retrieved delegate would be null and cause a NullReferenceException upon invokation.

    Far more interesting is the question what happens if one of there registered callbacks happens to change the delegate while it is being invoked! The answer can be found here: http://stackoverflow.com/questions/1609430/copying-delegates In short: One of the registered callbacks could change the delegate while it is being invoked, or – more specifically – could remove callbacks, resulting in the delegate being null. However, as delegates are immutable, the retrieved copy is guaranteed not to be null while it is being invoked 🙂

Questions? Comments? Suggestions? Your turn! :)