On Tuesday, 12 November 2013 at 22:36:22 UTC, Timon Gehr wrote:
- Every class in any imported module will need to show up in the generated code even if it is never used unless global static analysis is carried out on arguments to Object.factory.

- If I know the fully qualified name of a class, there are better ways to instantiate this class than passing a string containing that name to Object.factory in order to call the default constructor.

- The functionality provided by Object.factory is trivially replaced by a solution more specifically tailored to the problem at hand using compile-time reflection.

+ 1.

To test, I made a Factory template that works like this:

---
unittest
{
        import std.traits : fullyQualifiedName;

        interface I {}
        class A : I {}
        class B : I {}

        alias f = Factory!(I, A, B);

        static assert(is(f.Product == I));

        I a = f.create(fullyQualifiedName!A);
        assert(cast(A)a);

        I b = f.create(fullyQualifiedName!B);
        assert(cast(B)b);
}
---

Some notes:

* The first parameter, the Product parameter, which can be any class or interface, is required because CommonType is always Object when given a heterogeneous list of classes. I assume this is because of the difficulty of choosing a common interface when multiple interfaces are present.

* All subsequent parameters, the factory provider classes, are of course checked that they actually implement the Product, whether as a base class or an interface. Is a bit of a gotcha because AliasThis has to be "worked around" in the checking code.

* Implementation uses a sorted array instead of an AA because AAs can't be transferred from CT to RT yet.

* The array is immutable, so the same list is used for the same Factory across threads (but I suppose that has no real significance, just an observation).

* If the Product member is deemed unnecessary, it could just be a function template instead of a template with two members (Product and create).

Advantages over Object.factory:

* The opCall returns Product, not Object, so client code doesn't need to cast in most circumstances.

* `fullyQualifiedName` is used in the example because it internally uses `TypeInfo_Class.create`, which requires the full, internal names of the A and B types, which of course, are nested in a unittest. However, since the range of implementations are known, it could be amended to statically figure out a less strict naming scheme. In this case, just "A" and "B" could be made valid without ambiguity. Object.factory cannot practically do this.

* Interestingly, since it knows all the constructors, it could present an overload set of the constructors that all implementors support, with some implementation effort!

* Lookup has the opportunity to be a lot faster than Object.factory due to the smaller set of providers.

* The runtime list of providers does not contain types that aren't part of the set (duh), hence no bloat.

The disadvantage is that all implementing types must be passed at compile-time. That is the only advantage of Object.factory, AFAICS. As it seems like a very niche need that everyone has to pay for, I don't think Object.factory carries its weight.

Reply via email to