4

I have a tricky set of classes with generics. I can NOT change Container and GenericContainer, but I can change the rest.

  • the static version with .with(Configuration::initialise) works
  • the one .with(f) doesn't

The problem is the generic SELF parameter on the GenericContainer class, but I can't figure out the exact reason.

The example code is ready for copy/paste.

Initializer:

import java.util.function.BiConsumer;

public interface Initializer {
  <C extends Container<?>, S> C initialize(
    C container,
    BiConsumer<C, S> initializer
  );

  static <C extends Configuration.Container<?>> Initializer.Builder<C> init(
    C container
  ) {
    return new Initializer.Builder<>(container);
  }

  class Builder<C extends Configuration.Container<?>> {
    private final C container;

    public Builder(C container) {
      this.container = container;
    }

    public <S> C with(BiConsumer<C, S> initializer) {
      Initializer initService = null;
      return container;
    }
  }
}

Configuration:

import java.util.function.BiConsumer;
import javax.sql.DataSource;

public class Configuration {

  interface Container<SELF extends Container<SELF>> {}

  static class GenericContainer<SELF extends GenericContainer<SELF>>
    implements Container<SELF> {}

  // works
  public static void initialise(GenericContainer<?> container, DataSource ds) {}

  public static final GenericContainer<?> CONTAINER_1 = Initializer
    .init(new GenericContainer<>())
    .with(Configuration::initialise);

  // doesn't work
  static BiConsumer<GenericContainer<?>, DataSource> f = (con, ds) -> {};
  public static final GenericContainer<?> CONTAINER_2 = new Initializer.Builder<>(
    new GenericContainer<>()
  )
  .with(f);
}
Michael Böckling
  • 7,341
  • 6
  • 55
  • 76
  • I can see why it doesn't work on line 25 (using function variable), but not clear why it does work on line 18 (method reference). Perhaps method references have some special cases that apply to them. – David Roussel Jun 30 '20 at 07:53
  • Yes, its mystifying. Aside from that, do you have an idea what could be done to make the function variable case work? – Michael Böckling Jun 30 '20 at 08:00
  • It seems you can use lambdas and type parameters together. See https://stackoverflow.com/questions/22588518/lambda-expression-and-generic-method – David Roussel Jun 30 '20 at 08:06

1 Answers1

1

You can't do it because you need to define the type parameter of GenericContainer, but there is no syntax defined in the java standards to supply a generic type parameter to a lambda. As for why it works in the method reference I am not sure, but it might be type inference.

David Roussel
  • 5,788
  • 1
  • 30
  • 35
  • 1
    That took a while to wrap my head around. I suppose I would need to be able to do something like this, which is impossible: `static > BiConsumer, DataSource> f = (con, ds) -> {};` – Michael Böckling Jun 30 '20 at 08:56
  • Yes. It's all a bit annoying that the method reference vs lambda is not as interchangeable as you thought. And if you can't do a lambda, then it's not so easy to capture enclosing scoped variables – David Roussel Jul 01 '20 at 09:04