Monday, February 13, 2017

has a/is a/multiple inheritance/interface classes

I want the main class for my app to be basically one big event handler ie
class MonkeyMouse
  def onMouseUp(self)
    ...
  def onWheel(self, direction)
    ...
  def onCalendarUpdate(self)
    ...
  def onAlarm(self)
    ...
Right now I am doing that by doing multiple inheritance (using the "is a" solution)
class MonkeyMouse(timerAlarm.TimerAlarm, mouseEvent.MouseEvent, google_cal.GoogleCal, pianobar.PianoBar)
  def onMouseUp(self)
    ...
  def onWheel(self, direction)
    ...
  def onCalendarUpdate(self)
    ...
  def onAlarm(self)
    ...
The problem comes up when I create a method in 2 classes with the same name ie both the mouseevent and the timerevent classes both spawn threads calling a method that I initially called "worker". Obviously the name conflict caused issues.  Since it is me writing all the code I can obviously get around this issue, but also since it is me I have a high likelihood of causing conflicts for methods that do the same thing.

Compounding the issue is the desire to not spend huge amounts of time creating the perfect solution for a fun little app...

Another way to get around this would be to have the mouseevent class take a mouseevent handler class and have my main app inherit from each handler class, this would mean that the onXXX methods are the only place that I need to avoid conflict. This is kind of a pain in that I need to put try: / except around every call to make sure the method is defined.

The third way (using a "has a" solution) involves registering a callback method for each item that we are interested in - this still involves putting try/except around calls like self.mouseUpCallback() - however if we want to be lazy (cough) we can set all of our callbacks to be to null functions so then we just have to register for the callbacks that we care about and we can assume that the calls will work ie
class MouseEvent
   def __init__(self):
      super(MouseEvent, self).__init__()
      self.mouseUpCallback = self.nullFunc 
  def worker(self):
      ...
      self.mouseUpCallback()
      ....
  def nullFunc(self)
    pass 
Then all we need to do is write bind methods - I like this as it is the most elegant.

The only issue then is that we are not on a single thread that handles events "onMouseUp" could be called concurrently with "onAlarm" meaning they could have resource contention so we would need to put thread protection into our code. If we want to mitigate this (and avoid it in the onXxx code) we could instead create a event handler class and have the main thread run it in a loop. The other threads (mouse, calendar, alarm etc) would register their event and then signal the handler thread to wake it up using a condition. This would mean that the event handler class would be the only place that had to have mutex/thread awareness and the onXxx would be run synchronously avoiding many asynchronous headaches. I may have talked myself into doing it that way even though it is just me writing this app as it will let the app be more reusable...