//
// Nexus Core - a framework for developing distributed applications
// http://github.com/threerings/nexus/blob/master/LICENSE

package com.threerings.nexus.util;

/**
 * Used to communicate asynchronous results.
 */
public interface Callback<T>
{
    /** A callback that chains failure to the supplied delegate callback. */
    public static abstract class Chain<T> implements Callback<T> {
        public Chain (Callback<?> onFailure) {
            _onFailure = onFailure;
        }
        public void onFailure (Throwable cause) {
            _onFailure.onFailure(cause);
        }
        protected Callback<?> _onFailure;
    }

    /** A callback that does nothing, including nothing in the event of failure. Don't use this if
     * doing so will result in the suppression of errors! */
    public static final Callback<Object> NOOP = new Callback<Object>() {
        @Override public void onSuccess (Object result) {} // noop!
        @Override public void onFailure (Throwable cause) {} // noop!
    };

    /**
     * Called when the asynchronous request succeeded, supplying its result.
     */
    void onSuccess (T result);

    /**
     * Called when the asynchronous request failed, supplying a cause for failure.
     */
    void onFailure (Throwable cause);
}

//
// Nexus Core - a framework for developing distributed applications
// http://github.com/threerings/nexus/blob/master/LICENSE

package com.threerings.nexus.util;

/**
 * Used to communicate asynchronous results.
 */
public interface Callback<T>
{
    /** A callback that chains failure to the supplied delegate callback. */
    public static abstract class Chain<T> implements Callback<T> {
        public Chain (Callback<?> onFailure) {
            _onFailure = onFailure;
        }
        public void onFailure (Throwable cause) {
            _onFailure.onFailure(cause);
        }
        protected Callback<?> _onFailure;
    }

    public static class NoOp<T> implements Callback<T> {
        @Override public void onSuccess (T result) {
            // We're a No-Op - do nothing.
        }

        @Override public void onFailure (Throwable cause) {
            // We're a No-Op - do nothing.
        }
    }

    /**
     * Called when the asynchronous request succeeded, supplying its result.
     */
    void onSuccess (T result);

    /**
     * Called when the asynchronous request failed, supplying a cause for failure.
     */
    void onFailure (Throwable cause);
}

--- 
+++ 
@@ -20,15 +20,12 @@
         protected Callback<?> _onFailure;
     }
 
-    public static class NoOp<T> implements Callback<T> {
-        @Override public void onSuccess (T result) {
-            // We're a No-Op - do nothing.
-        }
-
-        @Override public void onFailure (Throwable cause) {
-            // We're a No-Op - do nothing.
-        }
-    }
+    /** A callback that does nothing, including nothing in the event of failure. Don't use this if
+     * doing so will result in the suppression of errors! */
+    public static final Callback<Object> NOOP = new Callback<Object>() {
+        @Override public void onSuccess (Object result) {} // noop!
+        @Override public void onFailure (Throwable cause) {} // noop!
+    };
 
     /**
      * Called when the asynchronous request succeeded, supplying its result.
Switch to a singleton NOOP. With proper variance, this can be used everywhere.

Proper variance is useful in general. When you want to use it, define your
service methods thusly:

  void detonateBombs (int targetId, Callback<? super String> onResult);

Then you can pass Callback<String> or Callback<Object> to the service method in
question.

Java uses what is called "use site" variance declarations, which means that
everyone that uses Callback has to repeat this "? super" boilerplate. Java
loves boilerplate, so perhaps it's apropos.

There is an alternative approach, called "declaration site" variance, which is
used by Scala. It allows the Callback declaration to say that it is
contravariant in type parameter T:

  trait Callback[-T] {
    def onSuccess (value :T)
    def onFailure (cause :Throwable)
  }

The "-T" means that everywhere someone says they take Callback[T], they
actually mean they take (the equivalent of) Callback[? super T]. Things "just
work" for everyone who uses Callback and there is much rejoicing. If only we
could write everything in Scala.
