vigna / fastutil

fastutil extends the Java™ Collections Framework by providing type-specific maps, sets, lists and queues.
Apache License 2.0
1.76k stars 196 forks source link

Support for specialized `Callable` functional interfaces for primitive data types #265

Closed abnercpp closed 2 years ago

abnercpp commented 2 years ago

I'm thinking about contributing to the project with a PR introducing Callable specializations for primitive data types.

I'm thinking the generated source files should end up something like this:

import static java.nio.charset.StandardCharsets.UTF_8;

import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.concurrent.Callable;

/**
 * POC for callables with primitive data types.
 */
public final class CallablesSample {

  public static void main(final String... args) {
    // propagates SQLException (not currently possible with regular `Callable<String>`)
    final ObjectCallable<String, SQLException> connectToDatabase =
        () -> DriverManager.getConnection("sample-url").getCatalog();
    // specialized version of `Callable<Byte>` (propagates generic Exception)
    final ByteCallable<?> getFirstByteFromUtf8 = () -> "utf8".getBytes(UTF_8)[0];
    // unchecked exception (similar to `Supplier<Boolean>`)
    final BooleanCallable<RuntimeException> callable = () -> true;
    final boolean a = callable.callAsBoolean();
    // ...
  }

  public interface ObjectCallable<V, E extends Exception> extends Callable<V> {
    @Override
    V call() throws E;
  }

  @FunctionalInterface
  public interface ByteCallable<E extends Exception> extends ObjectCallable<Byte, E> {
    @Override
    @Deprecated
    @SuppressWarnings("boxing")
    default Byte call() throws E {
      return callAsByte();
    }

    byte callAsByte() throws E;
  }

  @FunctionalInterface
  public interface ShortCallable<E extends Exception> extends ObjectCallable<Short, E> {
    @Override
    @Deprecated
    @SuppressWarnings("boxing")
    default Short call() throws E {
      return callAsShort();
    }

    short callAsShort() throws E;
  }

  @FunctionalInterface
  public interface IntCallable<E extends Exception> extends ObjectCallable<Integer, E> {
    @Override
    @Deprecated
    @SuppressWarnings("boxing")
    default Integer call() throws E {
      return callAsInt();
    }

    int callAsInt() throws E;
  }

  @FunctionalInterface
  public interface FloatCallable<E extends Exception> extends ObjectCallable<Float, E> {
    @Override
    @Deprecated
    @SuppressWarnings("boxing")
    default Float call() throws E {
      return callAsFloat();
    }

    float callAsFloat() throws E;
  }

  @FunctionalInterface
  public interface DoubleCallable<E extends Exception> extends ObjectCallable<Double, E> {
    @Override
    @Deprecated
    @SuppressWarnings("boxing")
    default Double call() throws E {
      return callAsDouble();
    }

    double callAsDouble() throws E;
  }

  @FunctionalInterface
  public interface LongCallable<E extends Exception> extends ObjectCallable<Long, E> {
    @Override
    @Deprecated
    @SuppressWarnings("boxing")
    default Long call() throws E {
      return callAsLong();
    }

    long callAsLong() throws E;
  }

  @FunctionalInterface
  public interface BooleanCallable<E extends Exception> extends ObjectCallable<Boolean, E> {
    @Override
    @Deprecated
    @SuppressWarnings("boxing")
    default Boolean call() throws E {
      return callAsBoolean();
    }

    boolean callAsBoolean() throws E;
  }
}

Should I commit?

vigna commented 2 years ago

I'm just not really convinced this is worth the effort. If you're using a Callable you're probably firing off a thread, an executor, etc. The cost of handling all this is orders of magnitude larger than the conversion of a single result.