0

I have seen advice that a Supplier can be used to create an instance of a parametrized class.

E.g. Here: "Instantiating object of type parameter" or here: "Create instance of generic type in Java?"

How to create the Supplier seems clear from the linked answers:

// Example of creating objects in linked answers
MyClass<StringBuilder> it = new MyClass<>(StringBuilder::new);
SomeContainer<String> stringContainer = new SomeContainer<>(String::new);

but how to use it for a recursive set of classes based on generic container doesn't seem to be clear.

My problem is that this Supplier methods itself has to be called as a parameter of the constructor for each recursive class. Example:

class SetOf<E> {
    // Supplier-based code from SO Q #75175
    private Supplier<E> supplier;
    SetOf(Supplier<E> supplier) { this.supplier = supplier; }
    createE() { return supplier.get(); }

    addToContainer(key) {
        E value = createE(); // I assume that's how it's used?
        this.add(key, value);
    }
}

The problem here is that if we are building container of containers thusly:

class SetOfThings extends SetOf<Thing> {}
class SetOfSetsOfThings extends SetOf<SetOfThings> {}
class SetOfSetOfSetsOfThings extends SetOf<SetOfSetOfThings> {}
SetOf<SetOfSetOfSetOfThings> root = new SetOf<>(SetOfSetOfThings::new);

So, what we are passing to the Supplier of outer class (SetOfSetOfSetOfThings) is the reference to constructor of inner class (SetOfSetOfThings) - BUT, when that SetOfSetOfThings() constructor will be called, it will be called with no parameters, meaning that there will be NO supplier for SetOfThings set in the SetOfSetOfThings object! (which means we can never create SetOfThings objects).

I suppose we can fix this 3-level chain somehow, by using Lambda syntax and passing a parameter (with value of SetOfThings::new) to SetOfSetOfThings::new in turn. But this only works because our chain is 3 levels deep - what if we have to instantiate 4-level deep chain with root class being SetOfSetOfSetsOfSetsOfThings?

This question is a very narrow Function/Supplier specific version of my more generic earlier question here (where comments pointed to both Supplier as an idea, and the linked answer showing how to use a supplier in general - neither of which work easily in case of recursive class hierarchy).

DVK
  • 119,765
  • 29
  • 201
  • 317

1 Answers1

1

You're going to need some kind of supplier passed to the constructor at any level, since the Thing at the base level ultimately has to come from somewhere. However, you can use Supplier<Thing> at every level like so:

class SetOfThings extends SetOf<Thing> {
    SetOfThings(Supplier<Thing> supplier) {
        super(supplier);
    }
}

class SetOfSetOfThings extends SetOf<SetOfThings> {
    SetOfSetOfThings(Supplier<Thing> supplier) {
        super(() -> new SetOfThings(supplier));
    }
}

class SetOfSetOfSetOfThings extends SetOf<SetOfSetOfThings> {
    SetOfSetOfSetOfThings(Supplier<Thing> supplier) {
        super(() -> new SetOfSetOfThings(supplier));
    }
}

Then you can do:

SetOf<SetOfSetOfSetOfThings> root = new SetOf<>(() -> new SetOfSetOfSetOfThings(Thing::new));

SetOfSetOfSetOfThings ssst = root.createE();
SetOfSetOfThings sst = ssst.createE();
SetOfThings st = sst.createE();
Thing t = st.createE();

EDIT: If you're just trying to create an instance of recursive SetOf type, you don't need subclasses:

SetOf<SetOf<SetOf<SetOf<Thing>>>> root = new SetOf<>(
        () -> new SetOf<>(
                () -> new SetOf<>(
                        () -> new SetOf<>(
                                Thing::new))));

And with a helper method to make it look nicer:

public static <E> Supplier<SetOf<E>> setsOf(Supplier<E> supplier) {
    return () -> new SetOf<>(supplier);
}

SetOf<SetOf<SetOf<SetOf<Thing>>>> root = new SetOf<>(setsOf(setsOf(setsOf(Thing::new))));
Sean Van Gorder
  • 3,223
  • 23
  • 25
  • The instance variables there are just to demonstrate that each level can create an instance of the one below it. `SetOf` will create `SetOfSetOfSetOfThings` instances. I'm not sure what else you expect it to do. – Sean Van Gorder Jul 03 '17 at 20:06
  • Also, just to be clear, the Thing does NOT need to be created - what need to be created are nested sets of sets of sets. E.g. I don't need supplier of Thing, at any of the levels. I need a supplier of the Set (or other container) object. Sorry for confusion – DVK Jul 03 '17 at 20:11
  • No, you need it at the `SetOfThings` level. If you're extending `SetOf` you must call its constructor, which needs an instance of `Supplier`. When you define a subclass without a constructor, Java implicitly generates a no-arg constructor that calls the superclass's no-arg constructor. Since `SetOf` does not have a no-arg constructor, it isn't possible to use this, you must define a constructor in the subclass. – Sean Van Gorder Jul 03 '17 at 20:19
  • Updated the answer with a way to make `SetOf>>>`, in case that's what you were after. – Sean Van Gorder Jul 03 '17 at 20:45