3

I have been thinking for a couple years now about using Throwable events and implementing a sort of event system that uses throw to dispatch an event, or let a different method handle it with throws.

The only problem is, Throwable is reserved for Errors and Exceptions. A google search shows zero (relevant) results on something like this. I'm assuming this is completely original or in the minority of event systems out there.

I know that the C# event system is similar to my idea (though I've never used it, only seen code fragments).

The question here is would it be abusive to create an event system that uses try-catch statements and throwables, which are really made for error handling? And would there be performance issues compared to a "vanilla" interface-Listener-with-Event-object event system?

Regardless, I will probably make an event system using this idea just to try it out (a little exercise).

I have made two examples. One of which uses "vanilla" event system, the other uses Throwables.

Vanilla:

public class Entity implements EntityListener {
  @Override
  public void entityEvent(EntityEvent e) {
    //...
  }
}

public interface EntityListener {
  public void entityEvent(EntityEvent e);
}

public static void main(String... args) {
  new Entity().entityEvent(new EntityEvent());
}

Throwable:

public class Class1 {

  public void logicalThrow() throws ThrowableEvent, HelloEvent, LogicEvent {
    if(something)
      throw new ThrowableEvent();
    else if (sayHello)
      throw new HelloEvent();
    else
      throw new LogicEvent();
  }
}

public class Class2 {
  private Class1 class1 = new Class1();

  public static void main(String... args) {
    try {
      class1.logicalThrow();
    } catch(ThrowableEvent e) {
      System.out.println("Event thrown: " + e.getClass().getName());
    } catch(HelloEvent e1) {
      System.out.println("Hello!");
    } catch(LogicEvent e2) {
      System.out.println("10 + 11 = 101");
    }
    // the other catches won't run since they inherit ThrowableEvent, 
    // but I put in the verbose catch statements for an example
  }
}
  • 8
    The biggest issue that comes to mind is that throwing only goes directly up the call stack, while part of the point of an event system is that in principle any object can listen to any event from any other object it can get a reference to. – Ixrec May 23 '15 at 23:22
  • I was thinking more along the lines of a central location where events can be sent to and dispatched (an EventHandler) which contains a maintained ArrayList of Listeners and Events. If I used the call stack as an EventHandler, an event would propagate up a the call stack, and the thread's UncaughtExceptionHandler would handle it if not surrounded by try-catch. If the exception is caught in a method however, the method would be a listener (and thus the class implementing it). It still has the same principle that you mentioned. This adds a level of scoping to Events. – AMDG May 23 '15 at 23:25
  • 2
    You mean like an event queue? I think that's how most event systems are actually implemented. Could you add to your question some explanation of how throwing would result in modifications to the central ArrayList? There are other obvious problems but knowing that would make it much easier to give a thorough answer. – Ixrec May 23 '15 at 23:30
  • Well, in this case, there would be no ArrayList. And if you want to know what kind of EventHandler I'm talking about, I use github.com/QuantumTheoryMC/QuantumAPI/blob/master/Client%20API/… – AMDG May 23 '15 at 23:52
  • @LinkTheProgrammer, when you said C# has implemented such eventing system, did you mean events are propagated using the keyword throw in C#? If so, it is not correct. Did you mean something else like bubbling in WPF? Can you please help in understanding your statement? – Siva Senthil May 26 '15 at 11:47
2

Would it be abusive to create an event system that uses try-catch statements and throwables, which are really made for error handling?

Abusive is an emotionally loaded term. And it is blatantly subjective ... unless you are measuring a standard that everyone concerned can agree is applicable.

What could that standard be?

  • It could be a particular style guide that the concerned parties have agreed to use.
  • "Industry Best Practice" is NOT a suitable standard because: 1) it is not codified, and 2) it changes, and 3) you won't get everyone to agree what it actually is.
  • It could be a set of "best practice" rules that the concerned parties have agreed on.

And who are the concerned parties? That is easy:

  • If this is personal project - it is just you.
  • If this is a project that someone is being paid to implement - the project team, maintenance team and (maybe) the customer.
  • If this is an open source project - the developers. (Downstream folks may want to have a say, but the reality is that they only have "rights" if they are contributing.)
  • And so on.

For the record, neither the old Sun Java Code Conventions or the Google Java style guide says anything about whether what you are proposing would be appropriate.

There is a common dogma that says that "exceptions should not be used for normal flow control" ... but it is based on a circular definition, and (IMO) not helpful.

This dogma is based (in part) on advice from the the Java designers. (That advice was influenced by the fact that early JVMs were not optimized with "exceptions as normal flow control" in mind. Again, there is circularity in the logic here.) However, I haven't yet managed to find this advice in any current normative Java documentation. (Tutorials are not normative ...)

And would there be performance issues compared to a "vanilla" interface-Listener-with-Event-object event system?

Potentially, yes.

One problem is that creating a Throwable instance results in the capture of the call stack. This is expensive. You can do things to optimize this:

  • Overriding the fillInStackTrace method to do nothing gets rid of most of the overhead.
  • In Java 7 and onwards, the JIT compiler can optimize some cases where exception stacks don't need to be captured.

The other think you have missed is that you can only use exceptions for event signalling within a single call stack, and for patterns of event handling where events are handled further up the call stack. These are significant limitations, and will render this approach impractical for many use-cases.

In short, this won't work as a general event handling system.

  • 1
    To be honest, I would never use something like this anyways. It's more of just an idea that I've had for a long time and wondered about it. What if... "I made an event system that uses Throwables?". Tell me, what would happen in an ideal implementation of said system? – AMDG May 24 '15 at 1:46
  • What do you mean by "what would happen"? Explain to me precisely how this (hypothetical) ideal system would work? – Stephen C May 24 '15 at 1:48
  • In my mind, what would happen is: the scope can now be limited to method only objects. Any method marked with throws allows a method that calls it to do something with it when the event is caught. I will edit my question to include two example classes. – AMDG May 24 '15 at 1:55
  • Please see updated question. – AMDG May 24 '15 at 2:35
  • I have. I think that my last sentence sums it up accurately. – Stephen C May 24 '15 at 10:41
3

I don't understand how would something like that work. After a method throws an exception, it stops executing and permanently gives up control to some exception handler. But after a method raises an event, it gives up control to the event handler only temporarily, and then continues executing.

I don't see how could you emulate temporarily giving up control using something that permanently gives up control very well. Exceptions were never meant for something like that, and I don't think you can make them do it.

  • My idea emphasizes a lot on using try-catch to catch the exception, which does not halt execution. If the method were to say, contain a throws statement, then any method that called it could implement an action for the event. – AMDG May 24 '15 at 1:36
  • It does halt execution of the current piece of code, when you resume, you're at some different point in the program. – svick May 24 '15 at 11:30
  • 1
    @svick It is true in most languages; but as an exception, look at Common Lisp's restartable condition system and you'll see it can bind handler that operate without unwinding the stack, and that you can even resume your work once it has been handled. This might be used as an event system. – coredump May 24 '15 at 13:38
  • Common Lisp supports first-class continuations, which makes all kinds of interesting control flow achievable. Most non-lisp languages don't, so have to make do with moving up and down the call stack in relatively simple ways. – Jules Sep 27 '15 at 16:40
1

In addition to the other drawbacks that other answers have posited, another is that the Throwable mechanism is designed to be overbearing i.e., it short-circuits normal processing wherever present. Imagine the following

 public void doSomething(){
    Foo it = new Foo();

    Bar something = it.doesSomething(); //anything thrown here will cause a hard stop here

    it.continuesDoingStuff(); //doesn't get executed

 }

In the snippet above, throwing an "event" in doesSomething will alter the flow of doSomething in what is arguably an unpleasant way; to the unwary user of your API, it may cause the program to skip continuesDoingStuff altogether. The event will register more as a side-effect, than an expected outcome, which arguably defeats the purpose of event-driven programming.

  • Well of course, but the program flows normally if caught, unless an exception is thrown within the catch. As you can see in my example... – AMDG May 26 '15 at 21:48
0

This could be a good strategy for a search algorithm.

Supose you have recursive algorithm that performs very deep searches.

When you found the element that satisfies your search criteria you can just throw an "OnFoundEvent".

If you found nothing, you can throw an "OnNotFoundEvent".

With this technique you skip all the backtracking mechanism caused by the return statement.

Pseudo code example:

public Object search(Criteria criteria) {
    try {
        performDeepSearch(criteria);
        return null; // should never reach this line
    } catch (OnFoundEvent found) {
        return found.object;
    } catch (OnNotFoundEvent notFound) {
        return null;
    }
}
  • 1
    Will you really save much? The backtracking still has to occur as the exception has to move up to where it is caught doing clean up on the way or does the call stack just disappear? – Bent Jun 30 '16 at 13:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.